home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / network / file-tra / wu-ftpd-.000 / wu-ftpd- / wu-ftpd-2.4-fixed / src / ftpd.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-06-03  |  74.9 KB  |  2,830 lines

  1. /* Copyright (c) 1985, 1988, 1990 Regents of the University of California.
  2.  * All rights reserved.
  3.  *
  4.  * Redistribution and use in source and binary forms, with or without
  5.  * modification, are permitted provided that the following conditions are
  6.  * met: 1. Redistributions of source code must retain the above copyright
  7.  * notice, this list of conditions and the following disclaimer. 2.
  8.  * Redistributions in binary form must reproduce the above copyright notice,
  9.  * this list of conditions and the following disclaimer in the documentation
  10.  * and/or other materials provided with the distribution. 3. All advertising
  11.  * materials mentioning features or use of this software must display the
  12.  * following acknowledgement: This product includes software developed by the
  13.  * University of California, Berkeley and its contributors. 4. Neither the
  14.  * name of the University nor the names of its contributors may be used to
  15.  * endorse or promote products derived from this software without specific
  16.  * prior written permission.
  17.  *
  18.  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
  19.  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20.  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21.  * DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE FOR
  22.  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  23.  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  24.  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  25.  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  26.  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  27.  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  28.  * SUCH DAMAGE. 
  29.  */
  30.  
  31. #ifndef lint
  32. char copyright[] =
  33. "@(#) Copyright (c) 1985, 1988, 1990 Regents of the University of California.\n\
  34.  All rights reserved.\n";
  35. #endif /* not lint */
  36.  
  37. #ifndef lint
  38. static char sccsid[] = "@(#)ftpd.c  5.40 (Berkeley) 7/2/91";
  39. #endif /* not lint */
  40.  
  41. /* FTP server. */
  42. #include "config.h"
  43.  
  44. #include <sys/types.h>
  45. #include <sys/param.h>
  46. #include <sys/stat.h>
  47. #include <sys/ioctl.h>
  48. #include <sys/socket.h>
  49. #include <sys/file.h>
  50. #include <sys/wait.h>
  51.  
  52. #ifdef AIX
  53. #include <sys/id.h>
  54. #include <sys/priv.h>
  55. #endif
  56.  
  57. #include <netinet/in.h>
  58. #include <netinet/in_system.h>
  59. #include <netinet/ip.h>
  60.  
  61. #define FTP_NAMES
  62. #include <arpa/ftp.h>
  63. #include <arpa/inet.h>
  64. #include <arpa/telnet.h>
  65.  
  66. #include <ctype.h>
  67. #include <stdio.h>
  68. #include <signal.h>
  69. #include <pwd.h>
  70. #include <setjmp.h>
  71. #include <netdb.h>
  72. #include <errno.h>
  73. #include <string.h>
  74. #include <varargs.h>
  75. #ifdef SYSSYSLOG
  76. #include <sys/syslog.h>
  77. #else
  78. #include <syslog.h>
  79. #endif
  80. #include <time.h>
  81. #include "conversions.h"
  82. #include "extensions.h"
  83. #include "pathnames.h"
  84.  
  85. #ifdef M_UNIX
  86. #include <arpa/nameser.h>
  87. #include <resolv.h>
  88. #endif
  89.  
  90. #if defined(SVR4) || defined(ISC)
  91. #include <fcntl.h>
  92. #endif
  93.  
  94. #ifdef HAVE_SYSINFO
  95. #include <sys/systeminfo.h>
  96. #endif
  97.  
  98. #ifdef SHADOW_PASSWORD
  99. #include <shadow.h>
  100. #endif
  101.  
  102. #ifdef KERBEROS
  103. #include <sys/types.h>
  104. #include <auth.h>
  105. #include <krb.h>
  106. #endif
  107.  
  108. #ifdef ULTRIX_AUTH
  109. #include <auth.h>
  110. #include <sys/svcinfo.h>
  111. #endif
  112.  
  113. #ifdef HAVE_DIRENT
  114. #include <dirent.h>
  115. #else
  116. #include <sys/dir.h>
  117. #endif
  118.  
  119. #ifndef TRUE
  120. #define  TRUE   1
  121. #endif
  122.  
  123. #ifndef FALSE
  124. #define  FALSE  !TRUE
  125. #endif
  126.  
  127. /* File containing login names NOT to be used on this machine. Commonly used
  128.  * to disallow uucp. */
  129. extern int errno;
  130. extern int pidfd;
  131. extern char *ctime(const time_t *);
  132. #ifndef NO_CRYPT_PROTO
  133. extern char *crypt(const char *, const char *);
  134. #endif
  135. extern char version[];
  136. extern char *home;              /* pointer to home directory for glob */
  137. extern FILE *ftpd_popen(char *program, char *type, int closestderr),
  138.  *fopen(const char *, const char *),
  139.  *freopen(const char *, const char *, FILE *);
  140. extern int ftpd_pclose(FILE *iop),
  141.   fclose(FILE *);
  142. extern char *getline(),
  143.  *realpath(char *pathname, char *result);
  144. extern char cbuf[];
  145. extern off_t restart_point;
  146.  
  147. struct sockaddr_in ctrl_addr;
  148. struct sockaddr_in data_source;
  149. struct sockaddr_in data_dest;
  150. struct sockaddr_in his_addr;
  151. struct sockaddr_in pasv_addr;
  152.  
  153. int data;
  154. jmp_buf errcatch,
  155.   urgcatch;
  156. int logged_in;
  157. struct passwd *pw;
  158. int debug;
  159. int timeout = 900;              /* timeout after 15 minutes of inactivity */
  160. int maxtimeout = 7200;          /* don't allow idle time to be set beyond 2
  161.                                  * hours */
  162. int logging;
  163. int log_commands = 1;
  164. int anonymous;
  165. int guest;
  166. int type;
  167. int form;
  168. int stru;                       /* avoid C keyword */
  169. int mode;
  170. int usedefault = 1;             /* for data transfers */
  171. int pdata = -1;                 /* for passive mode */
  172. int transflag;
  173. off_t file_size;
  174. off_t byte_count;
  175.  
  176. #if !defined(CMASK) || CMASK == 0
  177. #undef CMASK
  178. #define CMASK 002
  179. #endif
  180. mode_t defumask = CMASK;           /* default umask value */
  181. char tmpline[7];
  182. char hostname[MAXHOSTNAMELEN];
  183. char remotehost[MAXHOSTNAMELEN];
  184. char remoteaddr[MAXHOSTNAMELEN];
  185.  
  186. /* log failures     27-apr-93 ehk/bm */
  187. #ifdef LOG_FAILED
  188. #define MAXUSERNAMELEN    32
  189. char the_user[MAXUSERNAMELEN];
  190. #endif
  191.  
  192. /* Access control and logging passwords */
  193. int use_accessfile = 1;
  194. char guestpw[MAXHOSTNAMELEN];
  195. char privatepw[MAXHOSTNAMELEN];
  196. int nameserved = 0;
  197. extern char authuser[];
  198. extern int authenticated;
  199.  
  200. /* File transfer logging */
  201. int xferlog = 0;
  202. int log_outbound_xfers = 0;
  203. int log_incoming_xfers = 0;
  204.  
  205. /* Allow use of lreply(); this is here since some older FTP clients don't
  206.  * support continuation messages.  In violation of the RFCs... */
  207. int dolreplies = 1;
  208.  
  209. /* Spontaneous reply text.  To be sent along with next reply to user */
  210. char *autospout = NULL;
  211. int autospout_free = 0;
  212.  
  213. /* allowed on-the-fly file manipulations (compress, tar) */
  214. int mangleopts = 0;
  215.  
  216. /* number of login failures before attempts are logged and FTP *EXITS* */
  217. int lgi_failure_threshold = 5;
  218.  
  219. /* Timeout intervals for retrying connections to hosts that don't accept PORT
  220.  * cmds.  This is a kludge, but given the problems with TCP... */
  221. #define SWAITMAX    90          /* wait at most 90 seconds */
  222. #define SWAITINT    5           /* interval between retries */
  223.  
  224. int swaitmax = SWAITMAX;
  225. int swaitint = SWAITINT;
  226.  
  227. /* Mod by Lee Silverman 26 May 1994 to fix SIGNAL_TYPE never being defined. */
  228. #ifdef LINUX
  229. #define SIGNAL_TYPE void
  230. #endif /* linux? */
  231.  
  232. SIGNAL_TYPE lostconn(int sig);
  233. SIGNAL_TYPE randomsig(int sig);
  234. SIGNAL_TYPE myoob(int sig);
  235. FILE *getdatasock(char *mode),
  236.  *dataconn(char *name, off_t size, char *mode);
  237.  
  238. #ifdef SETPROCTITLE
  239. char **Argv = NULL;             /* pointer to argument vector */
  240. char *LastArgv = NULL;          /* end of argv */
  241. char proctitle[BUFSIZ];         /* initial part of title */
  242.  
  243. #endif /* SETPROCTITLE */
  244.  
  245. #ifdef KERBEROS
  246. void init_krb();
  247. void end_krb();
  248. char krb_ticket_name[100];
  249. #endif /* KERBEROS */
  250.  
  251. #ifdef ULTRIX_AUTH
  252. int ultrix_check_pass(char *passwd, char *xpasswd);
  253. #endif
  254.  
  255. /* ls program commands and options for lreplies on and off */
  256. char  ls_long[50];
  257. char  ls_short[50];
  258. struct aclmember *entry = NULL;
  259.  
  260. main(int argc, char **argv, char **envp)
  261. {
  262.     int addrlen,
  263.       on = 1;
  264. #ifdef IPTOS_LOWDELAY
  265.     int tos;
  266. #endif
  267.     char *cp;
  268.  
  269. #ifdef SecureWare
  270.     setluid(1);                         /* make sure there is a valid luid */
  271.     set_auth_parameters(argc,argv);
  272.     setreuid(0, 0);
  273. #endif
  274. #if defined(M_UNIX) && !defined(_M_UNIX)
  275.     res_init();                         /* bug in old (1.1.1) resolver     */
  276.     _res.retrans = 20;                  /* because of fake syslog in 3.2.2 */
  277.     setlogmask(LOG_UPTO(LOG_INFO));
  278. #endif
  279.  
  280.     addrlen = sizeof(his_addr);
  281.     if (getpeername(0, (struct sockaddr *) &his_addr, &addrlen) < 0) {
  282.         syslog(LOG_ERR, "getpeername (%s): %m", argv[0]);
  283. #ifndef DEBUG
  284.         exit(1);
  285. #endif
  286.     }
  287.     addrlen = sizeof(ctrl_addr);
  288.     if (getsockname(0, (struct sockaddr *) &ctrl_addr, &addrlen) < 0) {
  289.         syslog(LOG_ERR, "getsockname (%s): %m", argv[0]);
  290. #ifndef DEBUG
  291.         exit(1);
  292. #endif
  293.     }
  294. #ifdef IPTOS_LOWDELAY
  295.     tos = IPTOS_LOWDELAY;
  296.     if (setsockopt(0, IPPROTO_IP, IP_TOS, (char *) &tos, sizeof(int)) < 0)
  297.           syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  298. #endif
  299.  
  300.     data_source.sin_port = htons(ntohs(ctrl_addr.sin_port) - 1);
  301.     debug = 0;
  302. /* Mod By Lee Silverman 26 May 1994 to provide a logging facility */
  303. #ifdef LINUX
  304. #ifndef FACILITY
  305. #define FACILITY LOG_DAEMON
  306. #endif (FACIITY?)
  307. #endif (Linux?)
  308.  
  309. #ifdef FACILITY
  310.     openlog("ftpd", LOG_PID | LOG_NDELAY, FACILITY);
  311. #else
  312.     openlog("ftpd", LOG_PID);
  313. #endif
  314.  
  315. #ifdef SETPROCTITLE
  316.     /* Save start and extent of argv for setproctitle. */
  317.     Argv = argv;
  318.     while (*envp)
  319.         envp++;
  320.     LastArgv = envp[-1] + strlen(envp[-1]);
  321. #endif /* SETPROCTITLE */
  322.  
  323.     argc--, argv++;
  324.     while (argc > 0 && *argv[0] == '-') {
  325.         for (cp = &argv[0][1]; *cp; cp++)
  326.             switch (*cp) {
  327.  
  328.             case 'a':
  329.                 use_accessfile = 1;
  330.                 break;
  331.  
  332.             case 'A':
  333.                 use_accessfile = 0;
  334.                 break;
  335.  
  336.             case 'v':
  337.                 debug = 1;
  338.                 break;
  339.  
  340.             case 'd':
  341.                 debug = 1;
  342.                 break;
  343.  
  344.             case 'l':
  345.                 logging = 1;
  346.                 break;
  347.  
  348.             case 'L':
  349.                 log_commands = 1;
  350.                 break;
  351.  
  352.             case 'i':
  353.                 log_incoming_xfers = 1;
  354.                 break;
  355.  
  356.             case 'o':
  357.                 log_outbound_xfers = 1;
  358.                 break;
  359.  
  360.             case 't':
  361.                 timeout = atoi(++cp);
  362.                 if (maxtimeout < timeout)
  363.                     maxtimeout = timeout;
  364.                 goto nextopt;
  365.  
  366.             case 'T':
  367.                 maxtimeout = atoi(++cp);
  368.                 if (timeout > maxtimeout)
  369.                     timeout = maxtimeout;
  370.                 goto nextopt;
  371.  
  372.             case 'u':
  373.                 {
  374.                     int val = 0;
  375.  
  376.                     while (*++cp && *cp >= '0' && *cp <= '9')
  377.                         val = val * 8 + *cp - '0';
  378.                     if (*cp)
  379.                         fprintf(stderr, "ftpd: Bad value for -u\n");
  380.                     else
  381.                         defumask = val;
  382.                     goto nextopt;
  383.                 }
  384.  
  385.             default:
  386.                 fprintf(stderr, "ftpd: Unknown flag -%c ignored.\n",
  387.                         *cp);
  388.                 break;
  389.             }
  390.       nextopt:
  391.         argc--, argv++;
  392.     }
  393.     (void) freopen(_PATH_DEVNULL, "w", stderr);
  394.  
  395.     /* Checking for random signals ... */
  396. #ifdef SIGHUP
  397.     (void) signal(SIGHUP, randomsig);
  398. #endif
  399. #ifdef SIGINT
  400.     (void) signal(SIGINT, randomsig);
  401. #endif
  402. #ifdef SIGQUIT
  403.     (void) signal(SIGQUIT, randomsig);
  404. #endif
  405. #ifdef SIGILL
  406.     (void) signal(SIGILL, randomsig);
  407. #endif
  408. #ifdef SIGTRAP
  409.     (void) signal(SIGTRAP, randomsig);
  410. #endif
  411. #ifdef SIGIOT
  412.     (void) signal(SIGIOT, randomsig);
  413. #endif
  414. #ifdef SIGEMT
  415.     (void) signal(SIGEMT, randomsig);
  416. #endif
  417. #ifdef SIGFPE
  418.     (void) signal(SIGFPE, randomsig);
  419. #endif
  420. #ifdef SIGKILL
  421.     (void) signal(SIGKILL, randomsig);
  422. #endif
  423. #ifdef SIGBUS
  424.     (void) signal(SIGBUS, randomsig);
  425. #endif
  426. #ifdef SIGSEGV
  427.     (void) signal(SIGSEGV, randomsig);
  428. #endif
  429. #ifdef SIGSYS
  430.     (void) signal(SIGSYS, randomsig);
  431. #endif
  432. #ifdef SIGALRM
  433.     (void) signal(SIGALRM, randomsig);
  434. #endif
  435. #ifdef SIGSTOP
  436.     (void) signal(SIGSTOP, randomsig);
  437. #endif
  438. #ifdef SIGTSTP
  439.     (void) signal(SIGTSTP, randomsig);
  440. #endif
  441. #ifdef SIGTTIN
  442.     (void) signal(SIGTTIN, randomsig);
  443. #endif
  444. #ifdef SIGTTOU
  445.     (void) signal(SIGTTOU, randomsig);
  446. #endif
  447. #ifdef SIGIO
  448.     (void) signal(SIGIO, randomsig);
  449. #endif
  450. #ifdef SIGXCPU
  451.     (void) signal(SIGXCPU, randomsig);
  452. #endif
  453. #ifdef SIGXFSZ
  454.     (void) signal(SIGXFSZ, randomsig);
  455. #endif
  456. #ifdef SIGWINCH
  457.     (void) signal(SIGWINCH, randomsig);
  458. #endif
  459. #ifdef SIGVTALRM
  460.     (void) signal(SIGVTALRM, randomsig);
  461. #endif
  462. #ifdef SIGPROF
  463.     (void) signal(SIGPROF, randomsig);
  464. #endif
  465. #ifdef SIGUSR1
  466.     (void) signal(SIGUSR1, randomsig);
  467. #endif
  468. #ifdef SIGUSR2
  469.     (void) signal(SIGUSR2, randomsig);
  470. #endif
  471.  
  472. #ifdef SIGPIPE
  473.     (void) signal(SIGPIPE, lostconn);
  474. #endif
  475. #ifdef SIGCHLD
  476.     (void) signal(SIGCHLD, SIG_IGN);
  477. #endif
  478.  
  479. #ifdef SIGURG
  480.     if ((int) signal(SIGURG, myoob) < 0)
  481.         syslog(LOG_ERR, "signal: %m");
  482. #endif
  483.  
  484.     /* Try to handle urgent data inline */
  485. #ifdef SO_OOBINLINE
  486.     if (setsockopt(0, SOL_SOCKET, SO_OOBINLINE, (char *)&on, sizeof(int)) < 0)
  487.         syslog(LOG_ERR, "setsockopt (SO_OOBINLINE): %m");
  488. #endif
  489.  
  490. #ifdef  F_SETOWN
  491.     if (fcntl(fileno(stdin), F_SETOWN, getpid()) == -1)
  492.         syslog(LOG_ERR, "fcntl F_SETOWN: %m");
  493. #endif
  494.     dolog(&his_addr);
  495.     /* Set up default state */
  496.     data = -1;
  497.     type = TYPE_A;
  498.     form = FORM_N;
  499.     stru = STRU_F;
  500.     mode = MODE_S;
  501.     tmpline[0] = '\0';
  502.  
  503. #ifdef HAVE_SYSINFO
  504.     sysinfo(SI_HOSTNAME, hostname, sizeof (hostname));
  505. #else
  506.     (void) gethostname(hostname, sizeof (hostname));
  507. #endif
  508.  
  509.     access_init();
  510.     authenticate();
  511.     conv_init();
  512.  
  513.     if (is_shutdown(1) != 0) {
  514.         syslog(LOG_INFO, "connection refused (server shut down) from %s [%s]",
  515.                remotehost, remoteaddr);
  516.         reply(500, "%s FTP server shut down -- please try again later.",
  517.               hostname);
  518.         exit(0);
  519.     }
  520.     show_banner(220);
  521.  
  522.     entry = (struct aclmember *) NULL;
  523.     if (getaclentry("lslong", &entry) && ARG0 && strlen(ARG0) > 0) {
  524.           strcpy(ls_long,ARG0);
  525.       if (ARG1 && strlen(ARG1)) {
  526.              strcat(ls_long," ");
  527.          strcat(ls_long,ARG1);
  528.           }
  529.     } else {
  530. #ifdef SVR4
  531. #ifndef AIX
  532.           strcpy(ls_long,"/bin/ls -la");
  533. #else
  534.           strcpy(ls_long,"/bin/ls -lA");
  535. #endif
  536. #else
  537.           strcpy(ls_long,"/bin/ls -lgA");
  538. #endif
  539.     }
  540.     strcat(ls_long," %s");
  541.  
  542.     entry = (struct aclmember *) NULL;
  543.     if (getaclentry("lsshort", &entry) && ARG0 && strlen(ARG0) > 0) {
  544.           strcpy(ls_short,ARG0);
  545.       if (ARG1 && strlen(ARG1)) {
  546.              strcat(ls_short," ");
  547.              strcat(ls_short,ARG1);
  548.       }
  549.     } else {
  550. #ifdef SVR4
  551. #ifndef AIX
  552.           strcpy(ls_short,"/bin/ls -la");
  553. #else
  554.           strcpy(ls_short,"/bin/ls -lA");
  555. #endif
  556. #else
  557.           strcpy(ls_short,"/bin/ls -lgA");
  558. #endif
  559.     }
  560.     strcat(ls_short," %s");
  561.  
  562.     reply(220, "%s FTP server (%s) ready.", hostname, version);
  563.     (void) setjmp(errcatch);
  564.  
  565.     for (;;)
  566.         (void) yyparse();
  567.     /* NOTREACHED */
  568. }
  569.  
  570. SIGNAL_TYPE
  571. randomsig(int sig)
  572. {
  573.     syslog(LOG_ERR, "exiting on signal %d", sig);
  574.     chdir("/etc/tmp");
  575.     signal(SIGIOT, SIG_DFL);
  576.     signal(SIGILL, SIG_DFL);
  577.     abort();
  578.     /* dologout(-1); *//* NOTREACHED */
  579. }
  580.  
  581. SIGNAL_TYPE
  582. lostconn(int sig)
  583. {
  584.     if (debug)
  585.         syslog(LOG_DEBUG, "lost connection to %s [%s]", remotehost, remoteaddr);
  586.     dologout(-1);
  587. }
  588.  
  589. static char ttyline[20];
  590.  
  591. /* Helper function for sgetpwnam(). */
  592. char *
  593. sgetsave(char *s)
  594. {
  595.     char *new;
  596.     
  597.     new = (char *) malloc(strlen(s) + 1);
  598.  
  599.     if (new == NULL) {
  600.         perror_reply(421, "Local resource failure: malloc");
  601.         dologout(1);
  602.         /* NOTREACHED */
  603.     }
  604.     (void) strcpy(new, s);
  605.     return (new);
  606. }
  607.  
  608. /* Save the result of a getpwnam.  Used for USER command, since the data
  609.  * returned must not be clobbered by any other command (e.g., globbing). */
  610. struct passwd *
  611. sgetpwnam(char *name)
  612. {
  613.     static struct passwd save;
  614.     register struct passwd *p;
  615. #ifdef M_UNIX
  616.     struct passwd *ret = (struct passwd *) NULL;
  617. #endif
  618.     char *sgetsave(char *s);
  619.  
  620. #ifdef KERBEROS
  621.     register struct authorization *q;
  622. #endif /* KERBEROS */
  623.  
  624. #ifdef SecureWare
  625.     struct pr_passwd *pr;
  626. #endif
  627.  
  628. #ifdef KERBEROS
  629.     init_krb();
  630.     q = getauthuid(p->pw_uid);
  631.     end_krb();
  632. #endif /* KERBEROS */
  633.  
  634. #ifdef M_UNIX
  635. # ifdef SecureWare
  636.     if ((pr = getprpwnam(name)) == NULL)
  637.         goto DONE;
  638. # endif /* SecureWare */
  639.     if ((p = getpwnam(name)) == NULL)
  640.         goto DONE;
  641. #else   /* M_UNIX */
  642. # ifdef SecureWare
  643.     if ((pr = getprpwnam(name)) == NULL)
  644.         return((struct passwd *) pr);
  645. # endif /* SecureWare */
  646.     if ((p = getpwnam(name)) == NULL)
  647.         return (p);
  648. #endif  /* M_UNIX */
  649.  
  650.     if (save.pw_name)   free(save.pw_name);
  651.     if (save.pw_gecos)  free(save.pw_gecos);
  652.     if (save.pw_dir)    free(save.pw_dir);
  653.     if (save.pw_shell)  free(save.pw_shell);
  654.  
  655.     save = *p;
  656.  
  657.     save.pw_name = sgetsave(p->pw_name);
  658.  
  659. #ifdef KERBEROS
  660.     save.pw_passwd = sgetsave(q->a_password);
  661. #elif defined(SecureWare)
  662.      if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
  663.         save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
  664.      else
  665.         save.pw_passwd = sgetsave("");
  666. #else
  667.     save.pw_passwd = sgetsave(p->pw_passwd);
  668. #endif
  669.  
  670.     save.pw_gecos = sgetsave(p->pw_gecos);
  671.     save.pw_dir = sgetsave(p->pw_dir);
  672.     save.pw_shell = sgetsave(p->pw_shell);
  673. #ifdef M_UNIX
  674.     ret = &save;
  675. DONE:
  676.     endpwent();
  677. #endif
  678. #ifdef SecureWare
  679.     endprpwent();
  680. #endif
  681. #ifdef M_UNIX
  682.     return(ret);
  683. #else
  684.     return(&save);
  685. #endif
  686. }
  687.  
  688. int login_attempts;             /* number of failed login attempts */
  689. int askpasswd;                  /* had user command, ask for passwd */
  690.  
  691. /* USER command. Sets global passwd pointer pw if named account exists and is
  692.  * acceptable; sets askpasswd if a PASS command is expected.  If logged in
  693.  * previously, need to reset state.  If name is "ftp" or "anonymous", the
  694.  * name is not in _PATH_FTPUSERS, and ftp account exists, set anonymous and
  695.  * pw, then just return.  If account doesn't exist, ask for passwd anyway.
  696.  * Otherwise, check user requesting login privileges.  Disallow anyone who
  697.  * does not have a standard shell as returned by getusershell().  Disallow
  698.  * anyone mentioned in the file _PATH_FTPUSERS to allow people such as root
  699.  * and uucp to be avoided. */
  700. user(char *name)
  701. {
  702.     register char *cp;
  703.     char *shell;
  704.     char *getusershell();
  705.     int   why = 0;
  706.  
  707. #ifdef HOST_ACCESS                     /* 19-Mar-93    BM              */
  708.     if (!rhost_ok(name, remotehost, remoteaddr))
  709.     {
  710.             reply(530, "User %s access denied.", name);
  711.             syslog(LOG_NOTICE,
  712.                     "FTP LOGIN REFUSED (name in %s) FROM %s [%s], %s",
  713.                      _PATH_FTPHOSTS, remotehost, remoteaddr, name);
  714.             return;
  715.     }
  716. #endif
  717.  
  718. #ifdef LOG_FAILED                       /* 06-Nov-92    EHK             */
  719.     strncpy(the_user, name, MAXUSERNAMELEN - 1);
  720. #endif
  721.  
  722.     if (logged_in) {
  723.         if (anonymous || guest) {
  724.             reply(530, "Can't change user from guest login.");
  725.             return;
  726.         }
  727.         end_login();
  728.     }
  729.  
  730.     anonymous = 0;
  731.     acl_remove();
  732.  
  733.     if (!strcasecmp(name, "ftp") || !strcasecmp(name, "anonymous")) {
  734.       struct aclmember *entry = NULL;
  735.       int machineok=1;
  736.       char guestservername[MAXHOSTNAMELEN];
  737.       guestservername[0]='\0';
  738.  
  739.       if (checkuser("ftp") || checkuser("anonymous")) {
  740.           reply(530, "User %s access denied.", name);
  741.           syslog(LOG_NOTICE,
  742.            "FTP LOGIN REFUSED (ftp in /etc/ftpusers) FROM %s [%s], %s",
  743.            remotehost, remoteaddr, name);
  744.           return;
  745.           
  746.         /*
  747.         ** Algorithm used:
  748.         ** - if no "guestserver" directive is present,
  749.         **     anonymous access is allowed, for backward compatibility.
  750.         ** - if a "guestserver" directive is present,
  751.         **     anonymous access is restricted to the machines listed,
  752.         **     usually the machine whose CNAME on the current domain
  753.         **     is "ftp"...
  754.         **
  755.         ** the format of the "guestserver" line is
  756.         ** guestserver [<machine1> [<machineN>]]
  757.         ** that is, "guestserver" will forbid anonymous access on all machines
  758.         ** while "guestserver ftp inf" will allow anonymous access on
  759.         ** the two machines whose CNAMES are "ftp.enst.fr" and "inf.enst.fr".
  760.         **
  761.         ** if anonymous access is denied on the current machine,
  762.         ** the user will be asked to use the first machine listed (if any)
  763.         ** on the "guestserver" line instead:
  764.         ** 530- Guest login not allowed on this machine,
  765.         **      connect to ftp.enst.fr instead.
  766.         **
  767.         ** -- <Nicolas.Pioch@enst.fr>
  768.         */
  769.       } else if (getaclentry("guestserver", &entry)
  770.                  && ARG0 && strlen(ARG0) > 0) {
  771.         struct hostent *tmphostent;
  772.  
  773.         /*
  774.         ** if a "guestserver" line is present,
  775.         ** default is not to allow guest logins
  776.         */
  777.         machineok=0;
  778.  
  779.         if (hostname[0]
  780.             && ((tmphostent=gethostbyname(hostname)))) {
  781.  
  782.           /*
  783.           ** hostname is the only first part of the FQDN
  784.           ** this may or may not correspond to the h_name value
  785.           ** (machines with more than one IP#, CNAMEs...)
  786.           ** -> need to fix that, calling gethostbyname on hostname
  787.           **
  788.           ** WARNING!
  789.           ** for SunOS 4.x, you need to have a working resolver in the libc
  790.           ** for CNAMES to work properly.
  791.           ** If you don't, add "-lresolv" to the libraries before compiling!
  792.           */
  793.           char dns_localhost[MAXHOSTNAMELEN];
  794.           int machinecount;
  795.  
  796.           strncpy(dns_localhost,
  797.                   tmphostent->h_name,
  798.                   sizeof(dns_localhost));
  799.           dns_localhost[sizeof(dns_localhost)-1]='\0';
  800.  
  801.           for (machinecount=0;
  802.                entry->arg[machinecount] && (entry->arg[machinecount])[0];
  803.                machinecount++) {
  804.  
  805.             if ((tmphostent=gethostbyname(entry->arg[machinecount]))) {
  806.               /*
  807.               ** remember the name of the first machine for redirection
  808.               */
  809.  
  810.               if ((!machinecount) && tmphostent->h_name) {
  811.                 strncpy(guestservername, entry->arg[machinecount],
  812.                         sizeof(guestservername));
  813.                 guestservername[sizeof(guestservername)-1]='\0';
  814.               }
  815.  
  816.               if (!strcasecmp(tmphostent->h_name, dns_localhost)) {
  817.                 machineok++;
  818.                 break;
  819.               }
  820.             }
  821.           }
  822.         }
  823.       }
  824.       if (!machineok) {
  825.         if (guestservername[0])
  826.           reply(530,
  827.              "Guest login not allowed on this machine, connect to %s instead.",
  828.                 guestservername);
  829.         else
  830.           reply(530,
  831.                 "Guest login not allowed on this machine.");
  832.         syslog(LOG_NOTICE,
  833.                "FTP LOGIN REFUSED (localhost not in guestservers) FROM %s [%s], %s",
  834.                remotehost, remoteaddr, name);
  835.         /* End of the big patch -- Nap */
  836.  
  837.         } else if ((pw = sgetpwnam("ftp")) != NULL) {
  838.             anonymous = 1;      /* for the access_ok call */
  839.             if ((why = access_ok(530)) == 1) {
  840.                 askpasswd = 1;
  841.                 acl_setfunctions();
  842.                 reply(331, "Guest login ok, send your complete e-mail address as password.");
  843.             } else if (why == 0) {
  844.                 reply(530, "User %s access denied..", name);
  845.                 syslog(LOG_NOTICE,
  846.                        "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  847.                        remotehost, remoteaddr, name);
  848.                 anonymous = 0;
  849.             } else {
  850.                 reply(530, "User %s access denied.", name);
  851.                 syslog(LOG_NOTICE,
  852.                        "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  853.                        remotehost, remoteaddr, name);
  854.                 dologout(0);
  855.             }
  856.         } else {
  857.             reply(530, "User %s unknown.", name);
  858.             syslog(LOG_NOTICE,
  859.               "FTP LOGIN REFUSED (ftp not in /etc/passwd) FROM %s [%s], %s",
  860.                    remotehost, remoteaddr, name);
  861.         }
  862.         return;
  863.     }
  864.     if ((pw = sgetpwnam(name)) != NULL) {
  865.         if ((shell = pw->pw_shell) == NULL || *shell == 0)
  866.             shell = _PATH_BSHELL;
  867.         while ((cp = getusershell()) != NULL)
  868.             if (strcmp(cp, shell) == 0)
  869.                 break;
  870.         endusershell();
  871.         if (cp == NULL || checkuser(name)) {
  872.             reply(530, "User %s access denied...", name);
  873.             if (logging)
  874.                 syslog(LOG_NOTICE,
  875.                        "FTP LOGIN REFUSED (bad shell) FROM %s [%s], %s",
  876.                        remotehost, remoteaddr, name);
  877.             pw = (struct passwd *) NULL;
  878.             return;
  879.         }
  880.         /* if user is a member of any of the guestgroups, cause a chroot() */
  881.         /* after they log in successfully                                  */
  882.         guest = acl_guestgroup(pw);
  883.     }
  884.     if (access_ok(530) < 1) {
  885.         reply(530, "User %s access denied....", name);
  886.         syslog(LOG_NOTICE, "FTP LOGIN REFUSED (access denied) FROM %s [%s], %s",
  887.                remotehost, remoteaddr, name);
  888.         return;
  889.     } else
  890.         acl_setfunctions();
  891.  
  892.     reply(331, "Password required for %s.", name);
  893.     askpasswd = 1;
  894.     /* Delay before reading passwd after first failed attempt to slow down
  895.      * passwd-guessing programs. */
  896.     if (login_attempts)
  897.         sleep((unsigned) login_attempts);
  898. }
  899.  
  900. /* Check if a user is in the file _PATH_FTPUSERS */
  901. checkuser(char *name)
  902. {
  903.     register FILE *fd;
  904.     register char *p;
  905.     char line[BUFSIZ];
  906.  
  907.     if ((fd = fopen(_PATH_FTPUSERS, "r")) != NULL) {
  908.         while (fgets(line, sizeof(line), fd) != NULL)
  909.             if ((p = strchr(line, '\n')) != NULL) {
  910.                 *p = '\0';
  911.                 if (line[0] == '#')
  912.                     continue;
  913.                 if (strcmp(line, name) == 0) {
  914.                     (void) fclose(fd);
  915.                     return (1);
  916.                 }
  917.             }
  918.         (void) fclose(fd);
  919.     }
  920.     return (0);
  921. }
  922.  
  923. /* Terminate login as previous user, if any, resetting state; used when USER
  924.  * command is given or login fails. */
  925. end_login(void)
  926. {
  927.  
  928.     (void) seteuid((uid_t) 0);
  929.     if (logged_in)
  930.         logwtmp(ttyline, "", "");
  931.     pw = NULL;
  932.     logged_in = 0;
  933.     anonymous = 0;
  934.     guest = 0;
  935. }
  936.  
  937. int
  938. validate_eaddr(char *eaddr)
  939. {
  940.     int i,
  941.       host,
  942.       state;
  943.  
  944.     for (i = host = state = 0; eaddr[i] != '\0'; i++) {
  945.         switch (eaddr[i]) {
  946.         case '.':
  947.             if (!host)
  948.                 return 0;
  949.             if (state == 2)
  950.                 state = 3;
  951.             host = 0;
  952.             break;
  953.         case '@':
  954.             if (!host || state > 1 || !strncasecmp("ftp", eaddr + i - host, host))
  955.                 return 0;
  956.             state = 2;
  957.             host = 0;
  958.             break;
  959.         case '!':
  960.         case '%':
  961.             if (!host || state > 1)
  962.                 return 0;
  963.             state = 1;
  964.             host = 0;
  965.             break;
  966.         case '-':
  967.             break;
  968.         default:
  969.             host++;
  970.         }
  971.     }
  972.     if (((state == 3) && host > 1) || ((state == 2) && !host) ||
  973.         ((state == 1) && host > 1))
  974.         return 1;
  975.     else
  976.         return 0;
  977. }
  978.  
  979. pass(char *passwd)
  980. {
  981.     char *xpasswd,
  982.      *salt;
  983.  
  984. #ifdef ULTRIX_AUTH
  985.     int numfails;
  986. #endif /* ULTRIX_AUTH */
  987.  
  988.     if (logged_in || askpasswd == 0) {
  989.         reply(503, "Login with USER first.");
  990.         return;
  991.     }
  992.     askpasswd = 0;
  993.  
  994.     /* Disable lreply() if the first character of the password is '-' since
  995.      * some hosts don't understand continuation messages and hang... */
  996.  
  997.     if (*passwd == '-')
  998.         dolreplies = 0;
  999.     else
  1000.         dolreplies = 1;
  1001.  
  1002.     if (!anonymous) {           /* "ftp" is only account allowed no password */
  1003.         if (*passwd == '-')
  1004.             passwd++;
  1005. #ifdef SHADOW_PASSWORD
  1006.         if (pw) {
  1007.            struct spwd *spw = getspnam( pw->pw_name );
  1008.            if( !spw ) { pw->pw_passwd = ""; }
  1009.            else { pw->pw_passwd = spw->sp_pwdp; }
  1010.         }
  1011. #endif
  1012.  
  1013.         *guestpw = (char) NULL;
  1014.         if (pw == NULL)
  1015.             salt = "xx";
  1016.         else
  1017.             salt = pw->pw_passwd;
  1018. #ifdef KERBEROS
  1019.         xpasswd = crypt16(passwd, salt);
  1020. #else
  1021.         xpasswd = crypt(passwd, salt);
  1022. #endif
  1023.  
  1024. #ifdef ULTRIX_AUTH
  1025.         if ((numfails = ultrix_check_pass(passwd, xpasswd)) < 0) {
  1026. #else
  1027.         /* The strcmp does not catch null passwords! */
  1028.         if (pw == NULL || *pw->pw_passwd == '\0' ||
  1029.             strcmp(xpasswd, pw->pw_passwd)) {
  1030. #endif
  1031.             reply(530, "Login incorrect.");
  1032.  
  1033. #ifdef LOG_FAILED                       /* 27-Apr-93    EHK/BM             */
  1034.             syslog(LOG_INFO, "failed login from %s [%s], %s",
  1035.                               remotehost, remoteaddr, the_user);
  1036. #endif
  1037.             acl_remove();
  1038.  
  1039.             pw = NULL;
  1040.             if (++login_attempts >= lgi_failure_threshold) {
  1041.                 syslog(LOG_NOTICE, "repeated login failures from %s [%s]",
  1042.                        remotehost, remoteaddr);
  1043.                 exit(0);
  1044.             }
  1045.             return;
  1046.         }
  1047.     } else {
  1048.         char *pwin,
  1049.          *pwout = guestpw;
  1050.         struct aclmember *entry = NULL;
  1051.         int valid;
  1052.  
  1053.         if (getaclentry("passwd-check", &entry) &&
  1054.             ARG0 && strcasecmp(ARG0, "none")) {
  1055.  
  1056.             if (!strcasecmp(ARG0, "rfc822"))
  1057.                 valid = validate_eaddr(passwd);
  1058.             else if (!strcasecmp(ARG0, "trivial"))
  1059.                 valid = (strchr(passwd, '@') == NULL) ? 0 : 1;
  1060.             else
  1061.                 valid = 1;
  1062.  
  1063.             if (!valid && ARG1 && !strcasecmp(ARG1, "enforce")) {
  1064.                 lreply(530, "The response '%s' is not valid", passwd);
  1065.                 lreply(530, "Please use your e-mail address as your password");
  1066.                 lreply(530, "   for example: %s@%s or %s@",
  1067.                        authenticated ? authuser : "joe", remotehost,
  1068.                        authenticated ? authuser : "joe");
  1069.                 lreply(530, "[%s will be added if password ends with @]",
  1070.                        remotehost);
  1071.                 reply(530, "Login incorrect.");
  1072.         acl_remove();    
  1073.                 if (++login_attempts >= lgi_failure_threshold) {
  1074.                     syslog(LOG_NOTICE, "repeated login failures from %s [%s]",
  1075.                            remotehost, remoteaddr);
  1076.                     exit(0);
  1077.                 }
  1078.                 return;
  1079.             } else if (!valid) {
  1080.                 lreply(230, "The response '%s' is not valid", passwd);
  1081.                 lreply(230,
  1082.                 "Next time please use your e-mail address as your password");
  1083.                 lreply(230, "        for example: %s@%s",
  1084.                        authenticated ? authuser : "joe", remotehost);
  1085.             }
  1086.         }
  1087.         if (!*passwd) {
  1088.             strcpy(guestpw, "[none_given]");
  1089.         } else {
  1090.             int cnt = sizeof(guestpw) - 2;
  1091.  
  1092.             for (pwin = passwd; *pwin && cnt--; pwin++)
  1093.                 if (!isgraph(*pwin))
  1094.                     *pwout++ = '_';
  1095.                 else
  1096.                     *pwout++ = *pwin;
  1097.         }
  1098.     }
  1099.  
  1100.     /* if autogroup command applies to user's class change pw->pw_gid */
  1101.     if (anonymous)
  1102.         (void) acl_autogroup(pw);
  1103.  
  1104.     login_attempts = 0;         /* this time successful */
  1105.     (void) setegid((gid_t) pw->pw_gid);
  1106.     (void) initgroups(pw->pw_name, pw->pw_gid);
  1107.  
  1108.     /* open wtmp before chroot */
  1109.     (void) sprintf(ttyline, "ftp%d", getpid());
  1110.     logwtmp(ttyline, pw->pw_name, remotehost);
  1111.     logged_in = 1;
  1112.  
  1113.     /* if logging is enabled, open logfile before chroot */
  1114.     if (log_outbound_xfers || log_incoming_xfers)
  1115.         xferlog = open(_PATH_XFERLOG, O_WRONLY | O_APPEND | O_CREAT, 0660);
  1116.  
  1117.     expand_id();
  1118.  
  1119.     if (anonymous || guest) {
  1120.         /* We MUST do a chdir() after the chroot. Otherwise the old current
  1121.          * directory will be accessible as "." outside the new root! */
  1122.         if (anonymous) {
  1123.             if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1124.                 reply(550, "Can't set guest privileges.");
  1125.                 goto bad;
  1126.             }
  1127.         } else if (guest) {
  1128.             char *sp;
  1129.  
  1130.             /* determine root and home directory */
  1131.  
  1132.             if ((sp = strstr(pw->pw_dir, "/./")) == NULL) {
  1133.                 if (chroot(pw->pw_dir) < 0 || chdir("/") < 0) {
  1134.                     reply(550, "Can't set guest privileges.");
  1135.                     goto bad;
  1136.                 }
  1137.             } else {
  1138.                 *sp++ = '\0';
  1139.  
  1140.                 if (chroot(pw->pw_dir) < 0 || chdir(++sp) < 0) {
  1141.                     reply(550, "Can't set guest privileges.");
  1142.                     goto bad;
  1143.                 }
  1144.             }
  1145.         }
  1146.     } else {
  1147.         if (chdir(pw->pw_dir) < 0) {
  1148.             if (chdir("/") < 0) {
  1149.                 reply(530, "User %s: can't change directory to %s.",
  1150.                       pw->pw_name, pw->pw_dir);
  1151.                 goto bad;
  1152.             } else
  1153.                 lreply(230, "No directory! Logging in with home=/");
  1154.         }
  1155.     }
  1156.  
  1157. #ifdef AIX
  1158.     {
  1159.        /* AIX 3 lossage.  Don't ask.  It's undocumented.  */
  1160.        priv_t priv;
  1161.  
  1162.        priv.pv_priv[0] = 0;
  1163.        priv.pv_priv[1] = 0;
  1164.        setgroups(NULL, NULL);
  1165.        if (setpriv(PRIV_SET|PRIV_INHERITED|PRIV_EFFECTIVE|PRIV_BEQUEATH,
  1166.                    &priv, sizeof(priv_t)) < 0 ||
  1167.            setuidx(ID_REAL|ID_EFFECTIVE, (uid_t)pw->pw_uid) < 0 ||
  1168.            seteuid((uid_t)pw->pw_uid) < 0) {
  1169.                reply(550, "Can't set uid (AIX3).");
  1170.                goto bad;
  1171.        }
  1172.     }
  1173. # ifdef UID_DEBUG
  1174.     lreply(230, "ruid=%d, euid=%d, suid=%d, luid=%d", getuidx(ID_REAL),
  1175.          getuidx(ID_EFFECTIVE), getuidx(ID_SAVED), getuidx(ID_LOGIN));
  1176.     lreply(230, "rgid=%d, egid=%d, sgid=%d, lgid=%d", getgidx(ID_REAL),
  1177.          getgidx(ID_EFFECTIVE), getgidx(ID_SAVED), getgidx(ID_LOGIN));
  1178. #endif
  1179. #else
  1180.     if (seteuid((uid_t) pw->pw_uid) < 0) {
  1181.         reply(550, "Can't set uid.");
  1182.         goto bad;
  1183.     }
  1184. #endif
  1185.     /* * following two lines were inside the next scope... */
  1186.  
  1187.     show_message(230, LOG_IN);
  1188.     show_readme(230, LOG_IN);
  1189.  
  1190. #ifdef ULTRIX_AUTH
  1191.     if (!anonymous && numfails > 0) {
  1192.         lreply(230,
  1193.             "There have been %d unsuccessful login attempts on your account",
  1194.             numfails);
  1195.     }
  1196. #endif /* ULTRIX_AUTH */    
  1197.  
  1198.     if (anonymous) {
  1199.         (void) is_shutdown(0);  /* display any shutdown messages now */
  1200.  
  1201.         reply(230, "Guest login ok, access restrictions apply.");
  1202. #ifdef SETPROCTITLE
  1203.         sprintf(proctitle, "%s: anonymous/%.*s", remotehost,
  1204.                     sizeof(proctitle) - sizeof(remotehost) -
  1205.                     sizeof(": anonymous/"), passwd);
  1206.         setproctitle("%s", proctitle);
  1207. #endif /* SETPROCTITLE */
  1208.         if (logging)
  1209.             syslog(LOG_INFO, "ANONYMOUS FTP LOGIN FROM %s [%s], %s",
  1210.                    remotehost, remoteaddr, passwd);
  1211.     } else {
  1212.         reply(230, "User %s logged in.%s", pw->pw_name, guest ?
  1213.               "  Access restrictions apply." : "");
  1214. #ifdef SETPROCTITLE
  1215.         sprintf(proctitle, "%s: %s", remotehost, pw->pw_name);
  1216.         setproctitle(proctitle);
  1217. #endif /* SETPROCTITLE */
  1218.         if (logging)
  1219.             syslog(LOG_INFO, "FTP LOGIN FROM %s [%s], %s",
  1220.                    remotehost, remoteaddr, pw->pw_name);
  1221.     }
  1222.     home = pw->pw_dir;          /* home dir for globbing */
  1223.     (void) umask(defumask);
  1224.     return;
  1225.   bad:
  1226.     /* Forget all about it... */
  1227.     xferlog = 0;
  1228.     end_login();
  1229. }
  1230.  
  1231. char *
  1232. opt_string(int options)
  1233. {
  1234.     static char buf[100];
  1235.     char *ptr = buf;
  1236.  
  1237.     if ((options & O_COMPRESS) != (int) NULL)
  1238.         *ptr++ = 'C';
  1239.     if ((options & O_TAR) != (int) NULL)
  1240.         *ptr++ = 'T';
  1241.     if ((options & O_UNCOMPRESS) != (int) NULL)
  1242.         *ptr++ = 'U';
  1243.     if (options == 0)
  1244.         *ptr++ = '_';
  1245.     *ptr++ = '\0';
  1246.     return (buf);
  1247. }
  1248.  
  1249. retrieve(char *cmd, char *name)
  1250. {
  1251.     FILE *fin,
  1252.      *dout;
  1253.     struct stat st,
  1254.       junk;
  1255.     int (*closefunc) () = NULL;
  1256.     int options = 0;
  1257.     time_t start_time = time(NULL);
  1258.     static char *logname;
  1259.     char namebuf[MAXPATHLEN];
  1260.     struct convert *cptr;
  1261.  
  1262.     if (!cmd && stat(name, &st)) {
  1263.         char fnbuf[MAXPATHLEN],
  1264.          *ptr;
  1265.  
  1266.         cptr = cvtptr;
  1267.  
  1268.         if (cptr == NULL) {
  1269.             (void) reply(550, "%s: No such file OR directory.", name);
  1270.             return;
  1271.         }
  1272.  
  1273.         do {
  1274.             if (!(mangleopts & O_COMPRESS) && (cptr->options & O_COMPRESS))
  1275.                 continue;
  1276.             if (!(mangleopts & O_UNCOMPRESS) && (cptr->options & O_UNCOMPRESS))
  1277.                 continue;
  1278.             if (!(mangleopts & O_TAR) && (cptr->options & O_TAR))
  1279.                 continue;
  1280.  
  1281.             if ( (cptr->stripfix) && (cptr->postfix) ) {
  1282.                 int pfxlen = strlen(cptr->postfix);
  1283.         int sfxlen = strlen(cptr->stripfix);
  1284.                 int namelen = strlen(name);
  1285.                 (void) strcpy(fnbuf, name);
  1286.  
  1287.                 if (namelen <= pfxlen)
  1288.                     continue;
  1289.         if ((namelen - pfxlen + sfxlen) >= sizeof(fnbuf))
  1290.             continue;
  1291.  
  1292.         if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
  1293.             continue;
  1294.                 *(fnbuf + namelen - pfxlen) = '\0';
  1295.                 (void) strcat(fnbuf, cptr->stripfix);
  1296.                 if (stat(fnbuf, &st))
  1297.                     continue;
  1298.             } else if (cptr->postfix) {
  1299.                 int pfxlen = strlen(cptr->postfix);
  1300.                 int namelen = strlen(name);
  1301.  
  1302.                 if (namelen <= pfxlen)
  1303.                     continue;
  1304.                 (void) strcpy(fnbuf, name);
  1305.                 if (strcmp(fnbuf + namelen - pfxlen, cptr->postfix))
  1306.                     continue;
  1307.                 *(fnbuf + namelen - pfxlen) = (char) NULL;
  1308.                 if (stat(fnbuf, &st))
  1309.                     continue;
  1310.             } else if (cptr->stripfix) {
  1311.                 (void) strcpy(fnbuf, name);
  1312.                 (void) strcat(fnbuf, cptr->stripfix);
  1313.                 if (stat(fnbuf, &st))
  1314.                     continue;
  1315.             } else {
  1316.                 (void) reply(550, "%s: No such file OR directory.", name);
  1317.                 return;
  1318.             }
  1319.  
  1320.             if (S_ISDIR(st.st_mode)) {
  1321.                 if (!(cptr->types & T_DIR)) {
  1322.                     (void) reply(550, "Cannot %s directories.", cptr->name);
  1323.                     return;
  1324.                 }
  1325.                 if (cptr->options & O_TAR) {
  1326.                     strcpy(namebuf, fnbuf);
  1327.                     strcat(namebuf, "/.notar");
  1328.                     if (!stat(namebuf, &junk)) {
  1329.                         (void) reply(550,
  1330.                                   "Sorry, you may not TAR that directory.");
  1331.                         return;
  1332.                     }
  1333.                 }
  1334.             }
  1335.  
  1336.             if (S_ISREG(st.st_mode) && !(cptr->types & T_REG)) {
  1337.                 (void) reply(550, "Cannot %s plain files.", cptr->name);
  1338.                 return;
  1339.             }
  1340.             if (!S_ISREG(st.st_mode) && !S_ISDIR(st.st_mode)) {
  1341.                 (void) reply(550, "Cannot %s special files.", cptr->name);
  1342.                 return;
  1343.             }
  1344.             if (!(cptr->types & T_ASCII) && deny_badasciixfer(550, ""))
  1345.                 return;
  1346.  
  1347.             logname = fnbuf;
  1348.             options |= cptr->options;
  1349.  
  1350.             strcpy(namebuf, cptr->external_cmd);
  1351.             if ((ptr = strchr(namebuf, ' ')) != NULL)
  1352.                 *ptr = '\0';
  1353.             if (stat(namebuf, &st) != (int) NULL) {
  1354.                 syslog(LOG_ERR, "external command %s not found",
  1355.                        namebuf);
  1356.                 (void) reply(550,
  1357.                 "Local error: conversion program not found. Cannot %s file.",
  1358.                              cptr->name);
  1359.                 return;
  1360.             }
  1361.             (void) retrieve(cptr->external_cmd, fnbuf);
  1362.  
  1363.             goto dolog;
  1364.         } while ( (cptr = cptr->next) != NULL );
  1365.  
  1366.     } else
  1367.         logname = (char *) NULL;
  1368.  
  1369.     if (cmd == 0) {
  1370.         fin = fopen(name, "r"), closefunc = fclose;
  1371.         st.st_size = 0;
  1372.     } else {
  1373.         char line[BUFSIZ];
  1374.  
  1375.         (void) sprintf(line, cmd, name), name = line;
  1376.         fin = ftpd_popen(line, "r", 1), closefunc = ftpd_pclose;
  1377.         st.st_size = -1;
  1378. #ifdef HAVE_ST_BLKSIZE
  1379.         st.st_blksize = BUFSIZ;
  1380. #endif
  1381.     }
  1382.     if (fin == NULL) {
  1383.         if (errno != 0)
  1384.             perror_reply(550, name);
  1385.         return;
  1386.     }
  1387.     if (cmd == 0 &&
  1388.         (fstat(fileno(fin), &st) < 0 || (st.st_mode & S_IFMT) != S_IFREG)) {
  1389.         reply(550, "%s: not a plain file.", name);
  1390.         goto done;
  1391.     }
  1392.     if (restart_point) {
  1393.         if (type == TYPE_A) {
  1394.             register int i,
  1395.               n,
  1396.               c;
  1397.  
  1398.             n = restart_point;
  1399.             i = 0;
  1400.             while (i++ < n) {
  1401.                 if ((c = getc(fin)) == EOF) {
  1402.                     perror_reply(550, name);
  1403.                     goto done;
  1404.                 }
  1405.                 if (c == '\n')
  1406.                     i++;
  1407.             }
  1408.         } else if (lseek(fileno(fin), restart_point, L_SET) < 0) {
  1409.             perror_reply(550, name);
  1410.             goto done;
  1411.         }
  1412.     }
  1413.     dout = dataconn(name, st.st_size, "w");
  1414.     if (dout == NULL)
  1415.         goto done;
  1416. #ifdef HAVE_ST_BLKSIZE
  1417.     send_data(fin, dout, st.st_blksize);
  1418. #else
  1419.     send_data(fin, dout, BUFSIZ);
  1420. #endif
  1421.     (void) fclose(dout);
  1422.  
  1423.   dolog:
  1424.     if (log_outbound_xfers && xferlog && (cmd == 0)) {
  1425.         char msg[MAXPATHLEN];
  1426.         int xfertime = time(NULL) - start_time;
  1427.         time_t curtime = time(NULL);
  1428.         int loop;
  1429.  
  1430.         if (!xfertime)
  1431.             xfertime++;
  1432.         realpath(logname ? logname : name, namebuf);
  1433.         for (loop = 0; namebuf[loop]; loop++)
  1434.             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
  1435.                 namebuf[loop] = '_';
  1436.         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
  1437.                 ctime(&curtime),
  1438.                 xfertime,
  1439.                 remotehost,
  1440.                 byte_count,
  1441.                 namebuf,
  1442.                 (type == TYPE_A) ? 'a' : 'b',
  1443.                 opt_string(options),
  1444.                 'o',
  1445.                 anonymous ? 'a' : 'r',
  1446.                 anonymous ? guestpw : pw->pw_name,
  1447.                 authenticated,
  1448.                 authenticated ? authuser : "*"
  1449.             );
  1450.         write(xferlog, msg, strlen(msg));
  1451.     }
  1452.     data = -1;
  1453.     pdata = -1;
  1454.   done:
  1455.     if (closefunc)
  1456.         (*closefunc) (fin);
  1457. }
  1458.  
  1459. store(char *name, char *mode, int unique)
  1460. {
  1461.     FILE *fout, *din;
  1462.     struct stat st;
  1463.     int (*closefunc) ();
  1464.     char *gunique(char *local);
  1465.     time_t start_time = time(NULL);
  1466.  
  1467.     struct aclmember *entry = NULL;
  1468.  
  1469.     int fdout;
  1470.  
  1471. #ifdef OVERWRITE
  1472.     int overwrite = 1;
  1473.  
  1474. #endif /* OVERWRITE */
  1475.  
  1476. #ifdef UPLOAD
  1477.     int open_flags = (O_RDWR | O_CREAT |
  1478.               ((mode && *mode == 'a') ? O_APPEND : O_TRUNC));
  1479.  
  1480.     mode_t oldmask;
  1481.     int f_mode = -1,
  1482.       dir_mode,
  1483.       match_value = -1;
  1484.     uid_t uid;
  1485.     gid_t gid;
  1486.     uid_t oldid;
  1487.     int trunc = O_TRUNC;
  1488.     int valid = 0;
  1489.  
  1490. #endif /* UPLOAD */
  1491.  
  1492.     if (unique && stat(name, &st) == 0 &&
  1493.         (name = gunique(name)) == NULL)
  1494.         return;
  1495.  
  1496.     /*
  1497.      * check the filename, is it legal?
  1498.      */
  1499.     if ( (fn_check(name)) <= 0 )
  1500.         return;
  1501.  
  1502. #ifdef OVERWRITE
  1503.     /* if overwrite permission denied and file exists... then deny the user
  1504.      * permission to write the file. */
  1505.     while (getaclentry("overwrite", &entry) && ARG0 && ARG1 != NULL) {
  1506.         if (type_match(ARG1))
  1507.             if (strcmp(ARG0, "yes") != 0) {
  1508.                 overwrite = 0;
  1509.                 open_flags |= O_EXCL;
  1510.             }
  1511.     }
  1512.  
  1513.     if (!overwrite && !stat(name, &st)) {
  1514.         reply(553, "%s: Permission denied. (Overwrite)", name);
  1515.         return;
  1516.     }
  1517. #endif /* OVERWRITE */
  1518.  
  1519. #ifdef UPLOAD
  1520.     if ( (match_value = upl_check(name, &uid, &gid, &f_mode, &valid)) < 0 )
  1521.         return;
  1522.  
  1523.     /* Only truncate on open if the file is not to be appended to. */
  1524.     if (mode[0] == 'a' || (mode[0] == 'r' && mode[0] == '+') || restart_point)
  1525.         trunc = 0;
  1526.  
  1527.     /* if the user has an explicit new file mode, than open the file using
  1528.      * that mode.  We must take care to not let the umask affect the file
  1529.      * mode.
  1530.      * 
  1531.      * else open the file and let the default umask determine the file mode. */
  1532.     if (f_mode >= 0) {
  1533.         oldmask = umask(0000);
  1534.         fdout = open(name, open_flags, f_mode);
  1535.         umask(oldmask);
  1536.     } else
  1537.         fdout = open(name, open_flags, 0666);
  1538.  
  1539.     if (fdout < 0) {
  1540.         perror_reply(553, name);
  1541.         return;
  1542.     }
  1543.     /* if we have a uid and gid, then use them. */
  1544.  
  1545.     if (valid > 0) {
  1546.         oldid = geteuid();
  1547.         (void) seteuid((uid_t) 0);
  1548.         if ((fchown(fdout, uid, gid)) < 0) {
  1549.             (void) seteuid(oldid);
  1550.             perror_reply(550, "fchown");
  1551.             return;
  1552.         }
  1553.         (void) seteuid(oldid);
  1554.     }
  1555. #endif /* UPLOAD */
  1556.  
  1557.     if (restart_point)
  1558.         mode = "r+w";
  1559.  
  1560. #ifdef UPLOAD
  1561.     fout = fdopen(fdout, mode);
  1562. #else
  1563.     fout = fopen(name, mode);
  1564. #endif /* UPLOAD */
  1565.  
  1566.     closefunc = fclose;
  1567.     if (fout == NULL) {
  1568.         perror_reply(553, name);
  1569.         return;
  1570.     }
  1571.     if (restart_point) {
  1572.         if (type == TYPE_A) {
  1573.             register int i,
  1574.               n,
  1575.               c;
  1576.  
  1577.             n = restart_point;
  1578.             i = 0;
  1579.             while (i++ < n) {
  1580.                 if ((c = getc(fout)) == EOF) {
  1581.                     perror_reply(550, name);
  1582.                     goto done;
  1583.                 }
  1584.                 if (c == '\n')
  1585.                     i++;
  1586.             }
  1587.             /* We must do this seek to "current" position because we are
  1588.              * changing from reading to writing. */
  1589.             if (fseek(fout, 0L, L_INCR) < 0) {
  1590.                 perror_reply(550, name);
  1591.                 goto done;
  1592.             }
  1593.         } else if (lseek(fileno(fout), restart_point, L_SET) < 0) {
  1594.             perror_reply(550, name);
  1595.             goto done;
  1596.         }
  1597.     }
  1598.     din = dataconn(name, (off_t) - 1, "r");
  1599.     if (din == NULL)
  1600.         goto done;
  1601.     if (receive_data(din, fout) == 0) {
  1602.         if (unique)
  1603.             reply(226, "Transfer complete (unique file name:%s).",
  1604.                   name);
  1605.         else
  1606.             reply(226, "Transfer complete.");
  1607.     }
  1608.     (void) fclose(din);
  1609.  
  1610.   dolog:
  1611.     if (log_incoming_xfers && xferlog) {
  1612.         char namebuf[MAXPATHLEN],
  1613.           msg[MAXPATHLEN];
  1614.         int xfertime = time(NULL) - start_time;
  1615.         time_t curtime = time(NULL);
  1616.         int loop;
  1617.  
  1618.         if (!xfertime)
  1619.             xfertime++;
  1620.         realpath(name, namebuf);
  1621.         for (loop = 0; namebuf[loop]; loop++)
  1622.             if (isspace(namebuf[loop]) || iscntrl(namebuf[loop]))
  1623.                 namebuf[loop] = '_';
  1624.         sprintf(msg, "%.24s %d %s %d %s %c %s %c %c %s ftp %d %s\n",
  1625.                 ctime(&curtime),
  1626.                 xfertime,
  1627.                 remotehost,
  1628.                 byte_count,
  1629.                 namebuf,
  1630.                 (type == TYPE_A) ? 'a' : 'b',
  1631.                 opt_string(0),
  1632.                 'i',
  1633.                 anonymous ? 'a' : 'r',
  1634.                 anonymous ? guestpw : pw->pw_name,
  1635.                 authenticated,
  1636.                 authenticated ? authuser : "*"
  1637.             );
  1638.         write(xferlog, msg, strlen(msg));
  1639.     }
  1640.     data = -1;
  1641.     pdata = -1;
  1642.   done:
  1643.     (*closefunc) (fout);
  1644. }
  1645.  
  1646. FILE *
  1647. getdatasock(char *mode)
  1648. {
  1649.     int s,
  1650.       on = 1,
  1651.       tries;
  1652.  
  1653.     if (data >= 0)
  1654.         return (fdopen(data, mode));
  1655.     (void) seteuid((uid_t) 0);
  1656.     s = socket(AF_INET, SOCK_STREAM, 0);
  1657.     if (s < 0)
  1658.         goto bad;
  1659.     if (setsockopt(s, SOL_SOCKET, SO_REUSEADDR,
  1660.                    (char *) &on, sizeof(on)) < 0)
  1661.         goto bad;
  1662.     /* anchor socket to avoid multi-homing problems */
  1663.     data_source.sin_family = AF_INET;
  1664.     data_source.sin_addr = ctrl_addr.sin_addr;
  1665.     for (tries = 1;; tries++) {
  1666.         if (bind(s, (struct sockaddr *) &data_source,
  1667.                  sizeof(data_source)) >= 0)
  1668.             break;
  1669.         if (errno != EADDRINUSE || tries > 10)
  1670.             goto bad;
  1671.         sleep(tries);
  1672.     }
  1673. #if defined(M_UNIX) && !defined(_M_UNIX)  /* bug in old TCP/IP release */
  1674.     {
  1675.         struct linger li;
  1676.         li.l_onoff = 1;
  1677.         li.l_linger = 900;
  1678.         if (setsockopt(s, SOL_SOCKET, SO_LINGER,
  1679.           (char *)&li, sizeof(struct linger)) < 0) {
  1680.             syslog(LOG_WARNING, "setsockopt (SO_LINGER): %m");
  1681.             goto bad;
  1682.         }
  1683.     }
  1684. #endif
  1685.     (void) seteuid((uid_t) pw->pw_uid);
  1686.  
  1687. #ifdef IPTOS_THROUGHPUT
  1688.     on = IPTOS_THROUGHPUT;
  1689.     if (setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &on, sizeof(int)) < 0)
  1690.           syslog(LOG_WARNING, "setsockopt (IP_TOS): %m");
  1691. #endif
  1692.  
  1693.     return (fdopen(s, mode));
  1694.   bad:
  1695.     (void) seteuid((uid_t) pw->pw_uid);
  1696.     (void) close(s);
  1697.     return (NULL);
  1698. }
  1699.  
  1700. FILE *
  1701. dataconn(char *name, off_t size, char *mode)
  1702. {
  1703.     char sizebuf[32];
  1704.     FILE *file;
  1705.     int retry = 0;
  1706. #ifdef IPTOS_LOWDELAY
  1707.     int tos;
  1708. #endif
  1709.  
  1710.     file_size = size;
  1711.     byte_count = 0;
  1712.     if (size != (off_t) - 1)
  1713.         (void) sprintf(sizebuf, " (%ld bytes)", size);
  1714.     else
  1715.         (void) strcpy(sizebuf, "");
  1716.     if (pdata >= 0) {
  1717.         struct sockaddr_in from;
  1718.         int s,
  1719.           fromlen = sizeof(from);
  1720.  
  1721.         s = accept(pdata, (struct sockaddr *) &from, &fromlen);
  1722.         if (s < 0) {
  1723.             reply(425, "Can't open data connection.");
  1724.             (void) close(pdata);
  1725.             pdata = -1;
  1726.             return (NULL);
  1727.         }
  1728.         (void) close(pdata);
  1729.         pdata = s;
  1730. #ifdef IPTOS_LOWDELAY
  1731.         tos = IPTOS_LOWDELAY;
  1732.         (void) setsockopt(s, IPPROTO_IP, IP_TOS, (char *) &tos,
  1733.                           sizeof(int));
  1734.  
  1735. #endif
  1736.         reply(150, "Opening %s mode data connection for %s%s.",
  1737.               type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1738.         return (fdopen(pdata, mode));
  1739.     }
  1740.     if (data >= 0) {
  1741.         reply(125, "Using existing data connection for %s%s.",
  1742.               name, sizebuf);
  1743.         usedefault = 1;
  1744.         return (fdopen(data, mode));
  1745.     }
  1746.     if (usedefault)
  1747.         data_dest = his_addr;
  1748.     usedefault = 1;
  1749.     file = getdatasock(mode);
  1750.     if (file == NULL) {
  1751.         reply(425, "Can't create data socket (%s,%d): %s.",
  1752.               inet_ntoa(data_source.sin_addr),
  1753.               ntohs(data_source.sin_port), strerror(errno));
  1754.         return (NULL);
  1755.     }
  1756.     data = fileno(file);
  1757.     while (connect(data, (struct sockaddr *) &data_dest,
  1758.                    sizeof(data_dest)) < 0) {
  1759.         if ((errno == EADDRINUSE || errno == EINTR) && retry < swaitmax) {
  1760.             sleep((unsigned) swaitint);
  1761.             retry += swaitint;
  1762.             continue;
  1763.         }
  1764.         perror_reply(425, "Can't build data connection");
  1765.         (void) fclose(file);
  1766.         data = -1;
  1767.         return (NULL);
  1768.     }
  1769.     reply(150, "Opening %s mode data connection for %s%s.",
  1770.           type == TYPE_A ? "ASCII" : "BINARY", name, sizebuf);
  1771.     return (file);
  1772. }
  1773.  
  1774. /* Tranfer the contents of "instr" to "outstr" peer using the appropriate
  1775.  * encapsulation of the data subject to Mode, Structure, and Type.
  1776.  *
  1777.  * NB: Form isn't handled. */
  1778. send_data(FILE *instr, FILE *outstr, off_t blksize)
  1779. {
  1780.     register int c,
  1781.       cnt;
  1782.     register char *buf;
  1783.     int netfd,
  1784.       filefd;
  1785.  
  1786.     transflag++;
  1787.     if (setjmp(urgcatch)) {
  1788.         transflag = 0;
  1789.         return;
  1790.     }
  1791.     switch (type) {
  1792.  
  1793.     case TYPE_A:
  1794.         while ((c = getc(instr)) != EOF) {
  1795.             byte_count++;
  1796.             if (c == '\n') {
  1797.                 if (ferror(outstr))
  1798.                     goto data_err;
  1799.                 (void) putc('\r', outstr);
  1800.             }
  1801.             (void) putc(c, outstr);
  1802.         }
  1803.         fflush(outstr);
  1804.         transflag = 0;
  1805.         if (ferror(instr))
  1806.             goto file_err;
  1807.         if (ferror(outstr))
  1808.             goto data_err;
  1809.         reply(226, "Transfer complete.");
  1810.         return;
  1811.  
  1812.     case TYPE_I:
  1813.     case TYPE_L:
  1814.         if ((buf = (char *) malloc((u_int) blksize)) == NULL) {
  1815.             transflag = 0;
  1816.             perror_reply(451, "Local resource failure: malloc");
  1817.             return;
  1818.         }
  1819.         netfd = fileno(outstr);
  1820.         filefd = fileno(instr);
  1821.         while ((cnt = read(filefd, buf, (u_int) blksize)) > 0 &&
  1822.                write(netfd, buf, cnt) == cnt)
  1823.             byte_count += cnt;
  1824.         transflag = 0;
  1825.         (void) free(buf);
  1826.         if (cnt != 0) {
  1827.             if (cnt < 0)
  1828.                 goto file_err;
  1829.             goto data_err;
  1830.         }
  1831.         reply(226, "Transfer complete.");
  1832.         return;
  1833.     default:
  1834.         transflag = 0;
  1835.         reply(550, "Unimplemented TYPE %d in send_data", type);
  1836.         return;
  1837.     }
  1838.  
  1839.   data_err:
  1840.     transflag = 0;
  1841.     perror_reply(426, "Data connection");
  1842.     return;
  1843.  
  1844.   file_err:
  1845.     transflag = 0;
  1846.     perror_reply(551, "Error on input file");
  1847. }
  1848.  
  1849. /* Transfer data from peer to "outstr" using the appropriate encapulation of
  1850.  * the data subject to Mode, Structure, and Type.
  1851.  *
  1852.  * N.B.: Form isn't handled. */
  1853. receive_data(FILE *instr, FILE *outstr)
  1854. {
  1855.     register int c;
  1856.     int cnt,
  1857.       bare_lfs = 0;
  1858.     char buf[BUFSIZ];
  1859.  
  1860.     transflag++;
  1861.     if (setjmp(urgcatch)) {
  1862.         transflag = 0;
  1863.         return (-1);
  1864.     }
  1865.     switch (type) {
  1866.  
  1867.     case TYPE_I:
  1868.     case TYPE_L:
  1869.         while ((cnt = read(fileno(instr), buf, sizeof buf)) > 0) {
  1870.             if (write(fileno(outstr), buf, cnt) != cnt)
  1871.                 goto file_err;
  1872.             byte_count += cnt;
  1873.         }
  1874.         if (cnt < 0)
  1875.             goto data_err;
  1876.         transflag = 0;
  1877.         return (0);
  1878.  
  1879.     case TYPE_E:
  1880.         reply(553, "TYPE E not implemented.");
  1881.         transflag = 0;
  1882.         return (-1);
  1883.  
  1884.     case TYPE_A:
  1885.         while ((c = getc(instr)) != EOF) {
  1886.             byte_count++;
  1887.             if (c == '\n')
  1888.                 bare_lfs++;
  1889.             while (c == '\r') {
  1890.                 if (ferror(outstr))
  1891.                     goto data_err;
  1892.                 if ((c = getc(instr)) != '\n') {
  1893.                     (void) putc('\r', outstr);
  1894.                     if (c == '\0' || c == EOF)
  1895.                         goto contin2;
  1896.                 }
  1897.             }
  1898.             (void) putc(c, outstr);
  1899.           contin2:;
  1900.         }
  1901.         fflush(outstr);
  1902.         if (ferror(instr))
  1903.             goto data_err;
  1904.         if (ferror(outstr))
  1905.             goto file_err;
  1906.         transflag = 0;
  1907.         if (bare_lfs) {
  1908.             lreply(226, "WARNING! %d bare linefeeds received in ASCII mode", bare_lfs);
  1909.             printf("   File may not have transferred correctly.\r\n");
  1910.         }
  1911.         return (0);
  1912.     default:
  1913.         reply(550, "Unimplemented TYPE %d in receive_data", type);
  1914.         transflag = 0;
  1915.         return (-1);
  1916.     }
  1917.  
  1918.   data_err:
  1919.     transflag = 0;
  1920.     perror_reply(426, "Data Connection");
  1921.     return (-1);
  1922.  
  1923.   file_err:
  1924.     transflag = 0;
  1925.     perror_reply(452, "Error writing file");
  1926.     return (-1);
  1927. }
  1928.  
  1929. statfilecmd(char *filename)
  1930. {
  1931.     char line[BUFSIZ];
  1932.     FILE *fin;
  1933.     int c;
  1934.  
  1935.     if (anonymous && dolreplies)
  1936.         (void) sprintf(line, ls_long, filename);
  1937.     else
  1938.         (void) sprintf(line, ls_short, filename);
  1939.     fin = ftpd_popen(line, "r", 0);
  1940.     lreply(211, "status of %s:", filename);
  1941.     while ((c = getc(fin)) != EOF) {
  1942.         if (c == '\n') {
  1943.             if (ferror(stdout)) {
  1944.                 perror_reply(421, "control connection");
  1945.                 (void) ftpd_pclose(fin);
  1946.                 dologout(1);
  1947.                 /* NOTREACHED */
  1948.             }
  1949.             if (ferror(fin)) {
  1950.                 perror_reply(551, filename);
  1951.                 (void) ftpd_pclose(fin);
  1952.                 return;
  1953.             }
  1954.             (void) putc('\r', stdout);
  1955.         }
  1956.         (void) putc(c, stdout);
  1957.     }
  1958.     (void) ftpd_pclose(fin);
  1959.     reply(211, "End of Status");
  1960. }
  1961.  
  1962. statcmd(void)
  1963. {
  1964.     struct sockaddr_in *sin;
  1965.     u_char *a,
  1966.      *p;
  1967.  
  1968.     lreply(211, "%s FTP server status:", hostname);
  1969.     printf("     %s\r\n", version);
  1970.     printf("     Connected to %s", remotehost);
  1971.     if (!isdigit(remotehost[0]))
  1972.         printf(" (%s)", inet_ntoa(his_addr.sin_addr));
  1973.     printf("\r\n");
  1974.     if (logged_in) {
  1975.         if (anonymous)
  1976.             printf("     Logged in anonymously\r\n");
  1977.         else
  1978.             printf("     Logged in as %s\r\n", pw->pw_name);
  1979.     } else if (askpasswd)
  1980.         printf("     Waiting for password\r\n");
  1981.     else
  1982.         printf("     Waiting for user name\r\n");
  1983.     printf("     TYPE: %s", typenames[type]);
  1984.     if (type == TYPE_A || type == TYPE_E)
  1985.         printf(", FORM: %s", formnames[form]);
  1986.     if (type == TYPE_L)
  1987. #if NBBY == 8
  1988.         printf(" %d", NBBY);
  1989. #else
  1990.         printf(" %d", bytesize);/* need definition! */
  1991. #endif
  1992.     printf("; STRUcture: %s; transfer MODE: %s\r\n",
  1993.            strunames[stru], modenames[mode]);
  1994.     if (data != -1)
  1995.         printf("     Data connection open\r\n");
  1996.     else if (pdata != -1) {
  1997.         printf("     in Passive mode");
  1998.         sin = &pasv_addr;
  1999.         goto printaddr;
  2000.     } else if (usedefault == 0) {
  2001.         printf("     PORT");
  2002.         sin = &data_dest;
  2003.       printaddr:
  2004.         a = (u_char *) & sin->sin_addr;
  2005.         p = (u_char *) & sin->sin_port;
  2006. #define UC(b) (((int) b) & 0xff)
  2007.         printf(" (%d,%d,%d,%d,%d,%d)\r\n", UC(a[0]),
  2008.                UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2009. #undef UC
  2010.     } else
  2011.         printf("     No data connection\r\n");
  2012.     reply(211, "End of status");
  2013. }
  2014.  
  2015. fatal(char *s)
  2016. {
  2017.     reply(451, "Error in server: %s\n", s);
  2018.     reply(221, "Closing connection due to server error.");
  2019.     dologout(0);
  2020.     /* NOTREACHED */
  2021. }
  2022.  
  2023. #if defined (HAVE_VPRINTF)
  2024. /* VARARGS2 */
  2025. reply(va_alist)
  2026.   va_dcl
  2027. {
  2028.     int n;
  2029.     char *fmt;
  2030.     va_list ap;
  2031.     
  2032.     va_start(ap);
  2033.     /* first argument is always the return code */
  2034.     n = va_arg(ap, int);
  2035.     /* second argument is always fmt string     */
  2036.     fmt = va_arg(ap, char *);
  2037.  
  2038.     if (autospout != NULL) {
  2039.         char *ptr = autospout;
  2040.  
  2041.         printf("%d-", n);
  2042.         while (*ptr) {
  2043.             if (*ptr == '\n') {
  2044.                 fputs("\r\n", stdout);
  2045.                 if (*(++ptr))
  2046.                     printf("%03d-", n);
  2047.             } else {
  2048.                 putchar(*ptr++);
  2049.             }
  2050.         }
  2051.         if (*(--ptr) != '\n')
  2052.             printf("\r\n");
  2053.         if (autospout_free) {
  2054.             (void) free(autospout);
  2055.             autospout_free = 0;
  2056.         }
  2057.         autospout = 0;
  2058.     }
  2059.     printf("%d ", n);
  2060.     vprintf(fmt, ap);
  2061.     printf("\r\n");
  2062.     (void) fflush(stdout);
  2063.  
  2064.     if (debug) {
  2065.         char buf[BUFSIZ];
  2066.         (void) vsprintf(buf, fmt, ap);
  2067.  
  2068.         syslog(LOG_DEBUG, "<--- %d ", n);
  2069.         syslog(LOG_DEBUG, buf);
  2070.     }
  2071.  
  2072.     va_end(ap);
  2073. }
  2074.  
  2075. /* VARARGS2 */
  2076. lreply(va_alist)
  2077.   va_dcl
  2078. {
  2079.     va_list ap;
  2080.     int n;
  2081.     char *fmt;
  2082.  
  2083.     va_start(ap);
  2084.     /* first argument is always the return code */
  2085.     n = va_arg(ap, int);
  2086.     /* second argument is always fmt string     */
  2087.     fmt = va_arg(ap, char *);
  2088.  
  2089.     if (!dolreplies)
  2090.         return;
  2091.     printf("%d-", n);
  2092.     vprintf(fmt, ap);
  2093.     printf("\r\n");
  2094.     (void) fflush(stdout);
  2095.  
  2096.     if (debug) {
  2097.         char buf[BUFSIZ];
  2098.         (void) vsprintf(buf, fmt, ap);
  2099.  
  2100.         syslog(LOG_DEBUG, "<--- %d- ", n);
  2101.         syslog(LOG_DEBUG, buf);
  2102.     }
  2103.  
  2104.     va_end(ap);
  2105. }
  2106.  
  2107. #else
  2108. /* VARARGS2 */
  2109. reply(int n, char *fmt, int p0, int p1, int p2, int p3, int p4, int p5)
  2110. {
  2111.     if (autospout != NULL) {
  2112.         char *ptr = autospout;
  2113.  
  2114.         printf("%d-", n);
  2115.         while (*ptr) {
  2116.             if (*ptr == '\n') {
  2117.                 printf("\r\n");
  2118.                 if (*(++ptr))
  2119.                     printf("%d-", n);
  2120.             } else {
  2121.                 putchar(*ptr++);
  2122.             }
  2123.         }
  2124.         if (*(--ptr) != '\n')
  2125.             printf("\r\n");
  2126.         if (autospout_free) {
  2127.             (void) free(autospout);
  2128.             autospout_free = 0;
  2129.         }
  2130.         autospout = 0;
  2131.     }
  2132.     printf("%d ", n);
  2133.     printf(fmt, p0, p1, p2, p3, p4, p5);
  2134.     printf("\r\n");
  2135.     (void) fflush(stdout);
  2136.     if (debug) {
  2137.         syslog(LOG_DEBUG, "<--- %d ", n);
  2138.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  2139.     }
  2140. }
  2141.  
  2142. /* VARARGS2 */
  2143. lreply(int n, char *fmt, int p0, int p1, int p2, int p3, int p4, int p5)
  2144. {
  2145.     if (!dolreplies)
  2146.         return;
  2147.     printf("%d-", n);
  2148.     printf(fmt, p0, p1, p2, p3, p4, p5);
  2149.     printf("\r\n");
  2150.     (void) fflush(stdout);
  2151.     if (debug) {
  2152.         syslog(LOG_DEBUG, "<--- %d- ", n);
  2153.         syslog(LOG_DEBUG, fmt, p0, p1, p2, p3, p4, p5);
  2154.     }
  2155. }
  2156. #endif
  2157.  
  2158. ack(char *s)
  2159. {
  2160.     reply(250, "%s command successful.", s);
  2161. }
  2162.  
  2163. nack(char *s)
  2164. {
  2165.     reply(502, "%s command not implemented.", s);
  2166. }
  2167.  
  2168. /* ARGSUSED */
  2169. yyerror(char *s)
  2170. {
  2171.     char *cp;
  2172.  
  2173.     if ((cp = strchr(cbuf, '\n')) != NULL)
  2174.         *cp = '\0';
  2175.     reply(500, "'%s': command not understood.", cbuf);
  2176. }
  2177.  
  2178. delete(char *name)
  2179. {
  2180.     struct stat st;
  2181.  
  2182.     /*
  2183.      * delete permission?
  2184.      */
  2185.  
  2186.     if ( (del_check(name)) == 0 )
  2187.         return;
  2188.  
  2189.     if (lstat(name, &st) < 0) {
  2190.         perror_reply(550, name);
  2191.         return;
  2192.     }
  2193.     if ((st.st_mode & S_IFMT) == S_IFDIR) {
  2194.         if (rmdir(name) < 0) {
  2195.             perror_reply(550, name);
  2196.             return;
  2197.         }
  2198.         goto done;
  2199.     }
  2200.     if (unlink(name) < 0) {
  2201.         perror_reply(550, name);
  2202.         return;
  2203.     }
  2204.   done:
  2205.     {
  2206.         char path[MAXPATHLEN];
  2207.  
  2208.         realpath(name, path);
  2209.  
  2210.         if (anonymous) {
  2211.             syslog(LOG_NOTICE, "%s of %s [%s] deleted %s", guestpw, remotehost,
  2212.                    remoteaddr, path);
  2213.         } else {
  2214.             syslog(LOG_NOTICE, "%s of %s [%s] deleted %s", pw->pw_name,
  2215.                    remotehost, remoteaddr, path);
  2216.         }
  2217.     }
  2218.  
  2219.     ack("DELE");
  2220. }
  2221.  
  2222. cwd(char *path)
  2223. {
  2224.     struct aclmember *entry = NULL;
  2225.     char cdpath[MAXPATHLEN + 1];
  2226.  
  2227.     if (chdir(path) < 0) {
  2228.         /* alias checking */
  2229.         while (getaclentry("alias", &entry) && ARG0 && ARG1 != NULL) {
  2230.             if (!strcasecmp(ARG0, path)) {
  2231.                 if (chdir(ARG1) < 0)
  2232.                     perror_reply(550, path);
  2233.                 else {
  2234.                     show_message(250, C_WD);
  2235.                     show_readme(250, C_WD);
  2236.                     ack("CWD");
  2237.                 }
  2238.                 return;
  2239.             }
  2240.         }
  2241.     /* check for "cdpath" directories. */
  2242.     entry = (struct aclmember *) NULL;
  2243.         while (getaclentry("cdpath", &entry) && ARG0 != NULL) {
  2244.         strcpy(cdpath,ARG0);
  2245.         strcat(cdpath,"/");
  2246.         strcat(cdpath,path);
  2247.             if (chdir(cdpath) >= 0) {
  2248.                 show_message(250, C_WD);
  2249.                 show_readme(250, C_WD);
  2250.                 ack("CWD");
  2251.                 return;
  2252.             }
  2253.         }
  2254.         perror_reply(550,path);
  2255.     } else {
  2256.         show_message(250, C_WD);
  2257.         show_readme(250, C_WD);
  2258.         ack("CWD");
  2259.     }
  2260. }
  2261.  
  2262. makedir(char *name)
  2263. {
  2264.     uid_t uid;
  2265.     gid_t gid;
  2266.     int   valid = 0;
  2267.  
  2268.     /*
  2269.      * check the directory, can we mkdir here?
  2270.      */
  2271.     if ( (dir_check(name, &uid, &gid, &valid)) <= 0 )
  2272.         return;
  2273.  
  2274.     /*
  2275.      * check the filename, is it legal?
  2276.      */
  2277.     if ( (fn_check(name)) <= 0 )
  2278.         return;
  2279.  
  2280.     if (mkdir(name, 0777) < 0) {
  2281.         perror_reply(550, name);
  2282.     return;
  2283.     }
  2284.  
  2285.     reply(257, "MKD command successful.");
  2286. }
  2287.  
  2288. removedir(char *name)
  2289. {
  2290.     int c, d;  /* dummy variables */
  2291.         int valid = 0;
  2292.  
  2293.     /*
  2294.      * check the directory, can we rmdir here?
  2295.      */
  2296.     if ( (dir_check(name, &c, &d, &valid)) <= 0 )
  2297.         return;
  2298.  
  2299.     /*
  2300.      * delete permission?
  2301.      */
  2302.  
  2303.     if ( (del_check(name)) == 0 )
  2304.         return;
  2305.  
  2306.     if (rmdir(name) < 0)
  2307.         perror_reply(550, name);
  2308.     else
  2309.         ack("RMD");
  2310. }
  2311.  
  2312. pwd(void)
  2313. {
  2314.     char path[MAXPATHLEN + 1];
  2315. #ifdef HAVE_GETCWD
  2316.     extern char *getcwd();
  2317. #else
  2318.     extern char *getwd(char *);
  2319. #endif
  2320.  
  2321. #ifdef HAVE_GETCWD
  2322.     if (getcwd(path,MAXPATHLEN) == (char *) NULL)
  2323. #else
  2324.     if (getwd(path) == (char *) NULL)
  2325. #endif
  2326.         reply(550, "%s.", path);
  2327.     else
  2328.         reply(257, "\"%s\" is current directory.", path);
  2329. }
  2330.  
  2331. char *
  2332. renamefrom(char *name)
  2333. {
  2334.     struct stat st;
  2335.  
  2336.     if (lstat(name, &st) < 0) {
  2337.         perror_reply(550, name);
  2338.         return ((char *) 0);
  2339.     }
  2340.  
  2341.     /* if rename permission denied and file exists... then deny the user
  2342.      * permission to rename the file. 
  2343.      */
  2344.     while (getaclentry("rename", &entry) && ARG0 && ARG1 != NULL) {
  2345.         if (type_match(ARG1))
  2346.             if (strcmp(ARG0, "yes")) {
  2347.                 reply(553, "%s: Permission denied. (rename)", name);
  2348.                 return ((char *) 0);
  2349.             }
  2350.     }
  2351.  
  2352.     reply(350, "File exists, ready for destination name");
  2353.     return (name);
  2354. }
  2355.  
  2356. renamecmd(char *from, char *to)
  2357. {
  2358.  
  2359.     /*
  2360.      * check the filename, is it legal?
  2361.      */
  2362.     if ( (fn_check(to)) == 0 )
  2363.         return;
  2364.  
  2365.     if (rename(from, to) < 0)
  2366.         perror_reply(550, "rename");
  2367.     else
  2368.         ack("RNTO");
  2369. }
  2370.  
  2371. dolog(struct sockaddr_in *sin)
  2372. {
  2373.     struct hostent *hp;
  2374.     char *blah;
  2375.  
  2376. #ifdef    DNS_TRYAGAIN
  2377.     int num_dns_tries = 0;
  2378.     /*
  2379.      * 27-Apr-93    EHK/BM
  2380.      * far away connections might take some time to get their IP address
  2381.      * resolved. That's why we try again -- maybe our DNS cache has the
  2382.      * PTR-RR now. This code is sloppy. Far better is to check what the
  2383.      * resolver returned so that in case of error, there's no need to
  2384.      * try again.
  2385.      */
  2386. dns_again:
  2387.      hp = gethostbyaddr((char *) &sin->sin_addr,
  2388.                                 sizeof (struct in_addr), AF_INET);
  2389.  
  2390.      if ( !hp && ++num_dns_tries <= 1 ) {
  2391.         sleep(3);
  2392.         goto dns_again;         /* try DNS lookup once more     */
  2393.      }
  2394. #else
  2395.     hp = gethostbyaddr((char *)&sin->sin_addr, sizeof(struct in_addr), AF_INET);
  2396. #endif
  2397.  
  2398.     blah = inet_ntoa(sin->sin_addr);
  2399.  
  2400.     (void) strncpy(remoteaddr, blah, sizeof(remoteaddr));
  2401.  
  2402.     if (!strcmp(remoteaddr, "0.0.0.0")) {
  2403.         nameserved = 1;
  2404.         strncpy(remotehost, "localhost", sizeof(remotehost));
  2405.     } else {
  2406.         if (hp) {
  2407.             nameserved = 1;
  2408.             (void) strncpy(remotehost, hp->h_name, sizeof(remotehost));
  2409.         } else {
  2410.             nameserved = 0;
  2411.             (void) strncpy(remotehost, remoteaddr, sizeof(remotehost));
  2412.         }
  2413.     }
  2414.  
  2415. #ifdef SETPROCTITLE
  2416.     sprintf(proctitle, "%s: connected", remotehost);
  2417.     setproctitle(proctitle);
  2418. #endif /* SETPROCTITLE */
  2419.  
  2420.     if (logging)
  2421.         syslog(LOG_INFO, "connection from %s [%s]", remotehost,
  2422.                remoteaddr);
  2423. }
  2424.  
  2425. /* Record logout in wtmp file and exit with supplied status. */
  2426. dologout(int status)
  2427. {
  2428.     if (logged_in) {
  2429.         (void) seteuid((uid_t) 0);
  2430.         logwtmp(ttyline, "", "");
  2431.     }
  2432.     syslog(LOG_INFO, "FTP session closed");
  2433.     if (xferlog)
  2434.         close(xferlog);
  2435.     acl_remove();
  2436.     /* beware of flushing buffers after a SIGPIPE */
  2437.     _exit(status);
  2438. }
  2439.  
  2440. SIGNAL_TYPE
  2441. myoob(int sig)
  2442. {
  2443.     char *cp;
  2444.  
  2445.     /* only process if transfer occurring */
  2446.     if (!transflag)
  2447.         return;
  2448.     cp = tmpline;
  2449.     if (getline(cp, 7, stdin) == NULL) {
  2450.         reply(221, "You could at least say goodbye.");
  2451.         dologout(0);
  2452.     }
  2453.     upper(cp);
  2454.     if (strcmp(cp, "ABOR\r\n") == 0) {
  2455.         tmpline[0] = '\0';
  2456.         reply(426, "Transfer aborted. Data connection closed.");
  2457.         reply(226, "Abort successful");
  2458.         longjmp(urgcatch, 1);
  2459.     }
  2460.     if (strcmp(cp, "STAT\r\n") == 0) {
  2461.         if (file_size != (off_t) - 1)
  2462.             reply(213, "Status: %lu of %lu bytes transferred",
  2463.                   byte_count, file_size);
  2464.         else
  2465.             reply(213, "Status: %lu bytes transferred", byte_count);
  2466.     }
  2467. }
  2468.  
  2469. /* Note: a response of 425 is not mentioned as a possible response to the
  2470.  * PASV command in RFC959. However, it has been blessed as a legitimate
  2471.  * response by Jon Postel in a telephone conversation with Rick Adams on 25
  2472.  * Jan 89. */
  2473. passive(void)
  2474. {
  2475.     int len;
  2476.     register char *p,
  2477.      *a;
  2478.  
  2479.     pdata = socket(AF_INET, SOCK_STREAM, 0);
  2480.     if (pdata < 0) {
  2481.         perror_reply(425, "Can't open passive connection");
  2482.         return;
  2483.     }
  2484.     pasv_addr = ctrl_addr;
  2485.     pasv_addr.sin_port = 0;
  2486.     (void) seteuid((uid_t) 0);
  2487.     if (bind(pdata, (struct sockaddr *) &pasv_addr, sizeof(pasv_addr)) < 0) {
  2488.         (void) seteuid((uid_t) pw->pw_uid);
  2489.         goto pasv_error;
  2490.     }
  2491.     (void) seteuid((uid_t) pw->pw_uid);
  2492.     len = sizeof(pasv_addr);
  2493.     if (getsockname(pdata, (struct sockaddr *) &pasv_addr, &len) < 0)
  2494.         goto pasv_error;
  2495.     if (listen(pdata, 1) < 0)
  2496.         goto pasv_error;
  2497.     a = (char *) &pasv_addr.sin_addr;
  2498.     p = (char *) &pasv_addr.sin_port;
  2499.  
  2500. #define UC(b) (((int) b) & 0xff)
  2501.  
  2502.     reply(227, "Entering Passive Mode (%d,%d,%d,%d,%d,%d)", UC(a[0]),
  2503.           UC(a[1]), UC(a[2]), UC(a[3]), UC(p[0]), UC(p[1]));
  2504.     return;
  2505.  
  2506.   pasv_error:
  2507.     (void) close(pdata);
  2508.     pdata = -1;
  2509.     perror_reply(425, "Can't open passive connection");
  2510.     return;
  2511. }
  2512.  
  2513. /* Generate unique name for file with basename "local". The file named
  2514.  * "local" is already known to exist. Generates failure reply on error. */
  2515. char *
  2516. gunique(char *local)
  2517. {
  2518.     static char new[MAXPATHLEN];
  2519.     struct stat st;
  2520.     char *cp = strrchr(local, '/');
  2521.     int count = 0;
  2522.  
  2523.     if (cp)
  2524.         *cp = '\0';
  2525.     if (stat(cp ? local : ".", &st) < 0) {
  2526.         perror_reply(553, cp ? local : ".");
  2527.         return ((char *) 0);
  2528.     }
  2529.     if (cp)
  2530.         *cp = '/';
  2531.     (void) strcpy(new, local);
  2532.     cp = new + strlen(new);
  2533.     *cp++ = '.';
  2534.     for (count = 1; count < 100; count++) {
  2535.         (void) sprintf(cp, "%d", count);
  2536.         if (stat(new, &st) < 0)
  2537.             return (new);
  2538.     }
  2539.     reply(452, "Unique file name cannot be created.");
  2540.     return ((char *) 0);
  2541. }
  2542.  
  2543. /* Format and send reply containing system error number. */
  2544. perror_reply(int code, char *string)
  2545. {
  2546.     reply(code, "%s: %s.", string, strerror(errno));
  2547. }
  2548.  
  2549. static char *onefile[] =
  2550. {"", 0};
  2551.  
  2552. send_file_list(char *whichfiles)
  2553. {
  2554.     struct stat st;
  2555.     DIR *dirp = NULL;
  2556.  
  2557. #ifdef HAVE_DIRENT
  2558.     struct dirent *dir;
  2559. #else
  2560.     struct direct *dir;
  2561. #endif
  2562.  
  2563.     FILE *dout = NULL;
  2564.     register char **dirlist,
  2565.      *dirname;
  2566.     int simple = 0;
  2567.     char *strpbrk(const char *, const char *);
  2568.  
  2569.     if (strpbrk(whichfiles, "~{[*?") != NULL) {
  2570.         extern char **ftpglob(register char *v),
  2571.          *globerr;
  2572.  
  2573.         globerr = NULL;
  2574.         dirlist = ftpglob(whichfiles);
  2575.         if (globerr != NULL) {
  2576.             reply(550, globerr);
  2577.             return;
  2578.         } else if (dirlist == NULL) {
  2579.             errno = ENOENT;
  2580.             perror_reply(550, whichfiles);
  2581.             return;
  2582.         }
  2583.     } else {
  2584.         onefile[0] = whichfiles;
  2585.         dirlist = onefile;
  2586.         simple = 1;
  2587.     }
  2588.  
  2589.     if (setjmp(urgcatch)) {
  2590.         transflag = 0;
  2591.         return;
  2592.     }
  2593.     while ((dirname = *dirlist++) != NULL) {
  2594.         if (stat(dirname, &st) < 0) {
  2595.             /* If user typed "ls -l", etc, and the client used NLST, do what
  2596.              * the user meant. */
  2597.             if (dirname[0] == '-' && *dirlist == NULL && transflag == 0) {
  2598.                 retrieve("/bin/ls %s", dirname);
  2599.                 return;
  2600.             }
  2601.             perror_reply(550, whichfiles);
  2602.             if (dout != NULL) {
  2603.                 (void) fclose(dout);
  2604.                 transflag = 0;
  2605.                 data = -1;
  2606.                 pdata = -1;
  2607.             }
  2608.             return;
  2609.         }
  2610.         if ((st.st_mode & S_IFMT) == S_IFREG) {
  2611.             if (dout == NULL) {
  2612.                 dout = dataconn("file list", (off_t) - 1, "w");
  2613.                 if (dout == NULL)
  2614.                     return;
  2615.                 transflag++;
  2616.             }
  2617.             fprintf(dout, "%s%s\n", dirname,
  2618.                     type == TYPE_A ? "\r" : "");
  2619.             byte_count += strlen(dirname) + 1;
  2620.             continue;
  2621.         } else if ((st.st_mode & S_IFMT) != S_IFDIR)
  2622.             continue;
  2623.  
  2624.         if ((dirp = opendir(dirname)) == NULL)
  2625.             continue;
  2626.  
  2627.         while ((dir = readdir(dirp)) != NULL) {
  2628.             char nbuf[MAXPATHLEN];
  2629.  
  2630. #ifndef HAVE_DIRENT    /* does not have d_namlen */
  2631.             if (dir->d_name[0] == '.' && dir->d_namlen == 1)
  2632. #else
  2633.             if (dir->d_name[0] == '.' && (strlen(dir->d_name) == 1))
  2634. #endif
  2635.                 continue;
  2636. #ifndef HAVE_DIRENT    /* does not have d_namlen */
  2637.             if (dir->d_namlen == 2 && dir->d_name[0] == '.' &&
  2638.                 dir->d_name[1] == '.')
  2639. #else
  2640.             if ((strlen(dir->d_name) == 2) && dir->d_name[0] == '.' &&
  2641.                 dir->d_name[1] == '.')
  2642. #endif
  2643.                 continue;
  2644.  
  2645.             sprintf(nbuf, "%s/%s", dirname, dir->d_name);
  2646.  
  2647.             /* We have to do a stat to insure it's not a directory or special
  2648.              * file. */
  2649.             if (simple || (stat(nbuf, &st) == 0 &&
  2650.                            (st.st_mode & S_IFMT) == S_IFREG)) {
  2651.                 if (dout == NULL) {
  2652.                     dout = dataconn("file list", (off_t) - 1,
  2653.                                     "w");
  2654.                     if (dout == NULL)
  2655.                         return;
  2656.                     transflag++;
  2657.                 }
  2658.                 if (nbuf[0] == '.' && nbuf[1] == '/')
  2659.                     fprintf(dout, "%s%s\n", &nbuf[2],
  2660.                             type == TYPE_A ? "\r" : "");
  2661.                 else
  2662.                     fprintf(dout, "%s%s\n", nbuf,
  2663.                             type == TYPE_A ? "\r" : "");
  2664.                 byte_count += strlen(nbuf) + 1;
  2665.             }
  2666.         }
  2667.         (void) closedir(dirp);
  2668.     }
  2669.  
  2670.     if (dout == NULL)
  2671.         reply(550, "No files found.");
  2672.     else if (ferror(dout) != 0)
  2673.         perror_reply(550, "Data connection");
  2674.     else
  2675.         reply(226, "Transfer complete.");
  2676.  
  2677.     transflag = 0;
  2678.     if (dout != NULL)
  2679.         (void) fclose(dout);
  2680.     data = -1;
  2681.     pdata = -1;
  2682. }
  2683.  
  2684. #ifdef SETPROCTITLE
  2685. # ifndef setproctitle /* because of SCO, we use SCOproctitle instead */
  2686. /* clobber argv so ps will show what we're doing. (stolen from sendmail)
  2687.  * warning, since this is usually started from inetd.conf, it often doesn't
  2688.  * have much of an environment or arglist to overwrite. */
  2689.  
  2690. #ifdef HAVE_PSTAT
  2691. #include <sys/pstat.h>
  2692. #endif
  2693.  
  2694. /* VARARGS2 */
  2695. setproctitle(va_alist)
  2696.   va_dcl
  2697. {
  2698.     va_list ap;
  2699.     char *fmt;
  2700.  
  2701.     register char *p,
  2702.      *bp,
  2703.       ch;
  2704.     register int i;
  2705.     char buf[BUFSIZ];
  2706. #ifdef HAVE_PSTAT
  2707.     union pstun un;
  2708. #endif
  2709.  
  2710.     va_start(ap);
  2711.     /* first argument is always the fmt string */
  2712.     fmt = va_arg(ap, char *);
  2713.  
  2714.     (void) vsprintf(buf, fmt, ap);
  2715.     va_end(ap);
  2716.  
  2717.     /* make ps print our process name */
  2718.     p = Argv[0];
  2719.     *p++ = '-';
  2720.  
  2721.     i = strlen(buf);
  2722. #ifdef HAVE_PSTAT
  2723.     un.pst_command = buf;
  2724.     pstat(PSTAT_SETCMD, un, i, 0, 0);
  2725. #else
  2726.     if (i > LastArgv - p - 2) {
  2727.         i = LastArgv - p - 2;
  2728.         buf[i] = '\0';
  2729.     }
  2730.     bp = buf;
  2731.     while ((ch = *bp++) != (char) NULL)
  2732.         if (ch != '\n' && ch != '\r')
  2733.             *p++ = ch;
  2734.     while (p < LastArgv)
  2735.         *p++ = ' ';
  2736. #endif
  2737. }
  2738. #endif /* setproctitle */
  2739. #endif /* SETPROCTITLE */
  2740.  
  2741. #ifdef KERBEROS
  2742. /* thanks to gshapiro@wpi.wpi.edu for the following kerberosities */
  2743.  
  2744. void
  2745. init_krb()
  2746. {
  2747.     char hostname[100];
  2748.  
  2749. #ifdef HAVE_SYSINFO
  2750.     if (sysinfo(SI_HOSTNAME, hostname, sizeof (hostname)) < 0) {
  2751.         perror("sysinfo");
  2752. #else
  2753.     if (gethostname(hostname, sizeof(hostname)) < 0) {
  2754.         perror("gethostname");
  2755. #endif
  2756.         exit(1);
  2757.     }
  2758.     if (strchr(hostname, '.'))
  2759.         *(strchr(hostname, '.')) = 0;
  2760.  
  2761.     sprintf(krb_ticket_name, "/var/dss/kerberos/tkt/tkt.%d", getpid());
  2762.     krb_set_tkt_string(krb_ticket_name);
  2763.  
  2764.     config_auth();
  2765.  
  2766.     if (krb_svc_init("hesiod", hostname, (char *) NULL, 0, (char *) NULL,
  2767.                      (char *) NULL) != KSUCCESS) {
  2768.         fprintf(stderr, "Couldn't initialize Kerberos\n");
  2769.         exit(1);
  2770.     }
  2771. }
  2772.  
  2773. void
  2774. end_krb()
  2775. {
  2776.     unlink(krb_ticket_name);
  2777. }
  2778. #endif /* KERBEROS */
  2779.  
  2780. #ifdef ULTRIX_AUTH
  2781. static int
  2782. ultrix_check_pass(char *passwd, char *xpasswd)
  2783. {
  2784.     struct svcinfo *svp;
  2785.     int auth_status;
  2786.  
  2787.     if ((svp = getsvc()) == (struct svcinfo *) NULL) {
  2788.         syslog(LOG_WARNING, "getsvc() failed in ultrix_check_pass");
  2789.         return -1;
  2790.     }
  2791.     if (pw == (struct passwd *) NULL) {
  2792.         return -1;
  2793.     }
  2794.     if (((svp->svcauth.seclevel == SEC_UPGRADE) &&
  2795.         (!strcmp(pw->pw_passwd, "*")))
  2796.         || (svp->svcauth.seclevel == SEC_ENHANCED)) {
  2797.         if ((auth_status=authenticate_user(pw, passwd, "/dev/ttypXX")) >= 0) {
  2798.             /* Indicate successful validation */
  2799.             return auth_status;
  2800.         }
  2801.         if (auth_status < 0 && errno == EPERM) {
  2802.             /* Log some information about the failed login attempt. */
  2803.             switch(abs(auth_status)) {
  2804.             case A_EBADPASS:
  2805.                 break;
  2806.             case A_ESOFTEXP:
  2807.                 syslog(LOG_NOTICE, "password will expire soon for user %s",
  2808.                     pw->pw_name);
  2809.                 break;
  2810.             case A_EHARDEXP:
  2811.                 syslog(LOG_NOTICE, "password has expired for user %s",
  2812.                     pw->pw_name);
  2813.                 break;
  2814.             case A_ENOLOGIN:
  2815.                 syslog(LOG_NOTICE, "user %s attempted login to disabled acct",
  2816.                     pw->pw_name);
  2817.                 break;
  2818.             }
  2819.         }
  2820.     }
  2821.     else {
  2822.         if ((*pw->pw_passwd != '\0') && (!strcmp(xpasswd, pw->pw_passwd))) {
  2823.             /* passwd in /etc/passwd isn't empty && encrypted passwd matches */
  2824.             return 0;
  2825.         }
  2826.     }
  2827.     return -1;
  2828. }
  2829. #endif /* ULTRIX_AUTH */
  2830.